Tomcat not Shutting Down Completely (Tomcat 9.0.31)

Solution 1:

Issues like that is best handled from code.

Although you can use catalina.sh stop -force to terminate the Tomcat instance no matter what, the point here is that Tomcat thinks those threads are running for a reason, and terminating your threads might leave your application in an inconsistent state (if it is terminated halfway of writing something, for example).

If you know for a fact that no such thing could happen, use the -force switch when stopping Tomcat.

However, it is best to write the application to either mark the threads as daemons (by calling setDaemon(true) on the Thread instance), so they can be terminated whenever the VM exits, or (if the threads should not be killed at any time) register a shutdown hook by implementing ServletContextListener, and doing the shutdown chores in the contextDestroyed method. Here is a question on StackOverflow about installing a shutdown hook.

Solution 2:

You application is probably leaving a bunch of non-daemon threads running, so it will never shut down.

The thread you mention in your question is a TimerThread and Tomcat knows how to shut those down (almost) safely. Just add clearReferencesStopTimerThreads="true" to your application context:

<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="yourAppName"
         clearReferencesStopTimerThreads="true" />

However, as mentioned by Lacek, the proper way to deal with them is through a ServletContextListener or another mechanism to administer the Thread's lifecycle. Since you are using a Spring container I would add a TaskScheduler (<task:scheduler id="" pool-size="" />) to your ApplicationContext and inject it into every bean that needs scheduling a task. If your servlets need to schedule tasks, create a ScheduledExecutorService in a ServletContextListener and store a reference to it in the ServletContext.

PS: there is also a clearReferencesStopThreads attribute, but the description in Apache Tomcat Configuration Manual should give you a hint, when to use it:

If true, Tomcat attempts to terminate threads that have been started by the web application. Stopping threads is performed via the deprecated (for good reason) Thread.stop() method and is likely to result in instability. As such, enabling this should be viewed as an option of last resort in a development environment and is not recommended in a production environment. If not specified, the default value of false will be used. If this feature is enabled, web applications may take up to two seconds longer to stop as executor threads are given up to two seconds to stop gracefully before Thread.stop() is called on any remaining threads.