How to identify and remove Threads/ThreadLocals initiated from our webapp in Java? How to identify and remove Threads/ThreadLocals initiated from our webapp in Java? multithreading multithreading

How to identify and remove Threads/ThreadLocals initiated from our webapp in Java?


There is no solution to fix all threadlocal leaks in one go.Normally third party libraries using Threadlocal variables have some kind of cleanup API call which can be used to clear their local thread variables.

You have to check for all reported threadlocal leaks and find the correct way of disposing them in the corresponding library. You can do this in your CustomServletContextListener

examples:

log4j (javadoc):

LogManager.shutdown()

jdbc driver: (javadoc):

DriverManager.deregisterDriver(driver);

note: Also check for new versions of your 3rd party libs to check fox fixes concerning memory leaks (and/or thread local leaks).


Solution depends on the library that created these Threads/ThreadLocal-s.Basically you need to call library's cleanup code from your CustomServletContextListener.contextDestroyed() method.

So find what is the library and how to shut it down properly.


You can try this code to remove all ThreadLocal

private void cleanThreadLocals() {    try {        // Get a reference to the thread locals table of the current thread        Thread thread = Thread.currentThread();        Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");        threadLocalsField.setAccessible(true);        Object threadLocalTable = threadLocalsField.get(thread);        // Get a reference to the array holding the thread local variables inside the        // ThreadLocalMap of the current thread        Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");        Field tableField = threadLocalMapClass.getDeclaredField("table");        tableField.setAccessible(true);        Object table = tableField.get(threadLocalTable);        // The key to the ThreadLocalMap is a WeakReference object. The referent field of this object        // is a reference to the actual ThreadLocal variable        Field referentField = Reference.class.getDeclaredField("referent");        referentField.setAccessible(true);        for (int i=0; i < Array.getLength(table); i++) {            // Each entry in the table array of ThreadLocalMap is an Entry object            // representing the thread local reference and its value            Object entry = Array.get(table, i);            if (entry != null) {                // Get a reference to the thread local object and remove it from the table                ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);                threadLocal.remove();            }        }    } catch(Exception e) {        // We will tolerate an exception here and just log it        throw new IllegalStateException(e);    }}