转自
http://stackoverflow.com/questions/3869026/how-to-clean-up-threadlocals
The javadoc says this:
"Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
If your application or (if you are talking about request threads) container uses a thread pool that means that threads don't die. If necessary, you would need to deal with the thread locals yourself. The only clean way to do this is to call the ThreadLocal.remove()
method.
There are two reasons you might want to clean up thread locals for threads in a thread pool:
- to prevent memory (or hypothetically resource) leaks, or
- to prevent accidental leakage of information from one request to another via thread locals.
Thread local memory leaks should not normally be a major issue with bounded thread pools since any thread locals are likely to get overwritten eventually; i.e. when the thread is reused. However, if you make the mistake of creating a new ThreadLocal
instances over and over again (instead of using a static
variable to hold a singleton instance), the thread local values won't get overwritten, and will accumulate in each thread's threadlocals
map. This could result in a serious leak.
Assuming that you are talking about thread locals that are created / used during a webapp's processing of an HTTP request, then one way to avoid the thread local leaks is to register a ServletRequestListener
with your webapp's ServletContext
and implement the listener's requestDestroyed
method to cleanup the thread locals for the current thread.
Note that in this context you also need to consider the possibility of information leaking from one request to another.
附:clean threadLocal method(test passed):
1) create a ServletRequestListener
import java.lang.ref.Reference;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
public class ThreadLocalCleanUpListener implements ServletRequestListener {
private void cleanUpThreadLocals() throws Exception {
// 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 threadLocalsInThread = 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");
Method removeInThreadLocalMap = threadLocalMapClass.getDeclaredMethod(
"remove", ThreadLocal.class);
removeInThreadLocalMap.setAccessible(true);
Field tableField = threadLocalMapClass.getDeclaredField("table");
tableField.setAccessible(true);
Object table = tableField.get(threadLocalsInThread);
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);
Method getMethod = Reference.class.getDeclaredMethod("get");
if (entry != null) {
ThreadLocal threadLocal = (ThreadLocal) getMethod.invoke(entry);
System.out.println(threadLocal);
removeInThreadLocalMap
.invoke(threadLocalsInThread, threadLocal);
}
}
}
@Override
public void requestDestroyed(ServletRequestEvent paramServletRequestEvent) {
System.out.println("destory");
try {
cleanUpThreadLocals();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void requestInitialized(ServletRequestEvent paramServletRequestEvent) {
System.out.println("init");
}
}
2) add below in web.xml:
xxx.xxx.ThreadLocalCleanUpListener