javamultithreadingtomcatshutdown-hook

ShutdownHooks on Tomcat for Threads


I am currently starting some threads in Servlet class like this:

public class GTCInitServlet extends HttpServlet implements Runnable {

    public GTCInitServlet() {
        super();
    }


    public void init(ServletConfig config) throws ServletException {

        .
        .
        .
        .

        // Start ATC initialisation and then return so server is not blocked
        new Thread(this).start();       
    }


    public void run() {

        try {

            .
            .
            .
            Somne thread code
            .
            .
            .
            
            // Create ATC instance to force initialisation
            new GtcTypeController(gtcType);

            // Assume all is OK
            GtcInit.setReturnMessage(gtcType, "Initialization status = OK");    

        } catch (Throwable t) {

            GtcInit.setThrowable(gtcType, t);
            GtcInit.setReturnMessage(gtcType, t.getMessage());
        }
    }

    .
    .
    .
    .
    

    /**
     * Override javax.servlet.GenericServlet#destroy()
     */
    public void destroy() {
        super.destroy();
    }
}

When I shutdown tomcat, there are a lot of threads that stay open. And in the tomcat logs, I see messages like:

15-Jun-2021 01:05:53.302 WARNING [Catalina-utility-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [GTC] appears to have started a thread named [RequestListScheduler] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.PriorityBlockingQueue.take(PriorityBlockingQueue.java:549)
 com.att.logicalprovisioning.atc.RequestListScheduler.getNextRequestTarget(RequestListScheduler.java:97)
 com.att.logicalprovisioning.atc.RequestListScheduler.run(RequestListScheduler.java:51)

I Googled for some info for a clean shutdown of Tomcat and I stumbled across shutdown hooks. But most of the examples I saw were with ServletContextListener. Is there a way to to it when I extend HttpServlet?

Any pointers would be helpful.


Solution

  • Your servlet should not lose the references to objects that create threads.

    Since your servlet creates a GtcTypeController, which starts a RequestListScheduler, you should save the reference of the first in the servlet:

    synchronized (this) {
        this.gtcTypeController = new GtcTypeController(gtcType);
    }
    

    and implement a method (let's call it GtcTypeController#destroy()), which will be called to stop the RequestListScheduler. Therefore your GTCInitServlet should look like:

    @Override
    public void destroy() {
        synchronized (this) {
            if (gtcTypeController != null) {
                gtcTypeController.destroy();
            } else {
                // You should also deal with the case when the anonymous
                // Thread started in `init()` didn't exit yet. This happens, when `init()` and
                // `destroy()` are called in a rapid sequence()
            }
        }
    }