ThreadLocal的结构
每个线程有维护了一个ThreadLocalMap,这个ThreadLocalMap的key是ThreadLocal引用,value是ThreadLocal变量真正的值,这个ThreadLocalMap的Entry的key是弱引用,value是强引用。
为什么使用弱引用?
执行以下测试代码的时候:
当main线程新建线程调用testThreadLocal时,引用关系是这样的:
当testThreadLocal执行完成后,testThreadLocal方法栈出栈,引用2和引用3就不存在了,当main方法执行完成后,main方法栈帧出栈,线程销毁,thread引用也不存在了,这时候堆中的所有对象都会被回收,不会出现内存泄露。
但是,如果线程是线程池中的线程,引用1将一直存在,当testThreadLocal执行完后,引用2和引用3不存在了,如果发生了GC,堆中的threadLocalValue这个对象只被一个弱(引用5)所引用,将会被回收,回收后Entry的key为null,但是value依然还存在。
但是在每次调用set和get方法都会去检查key为null的Entry将value也设置成null,这样的话就多了一层保障。即使没有主动调用remove方法,只要调用了set和get就会将没用的对象引用清除。如果Entry的key不使用弱引用的话,就没办法实现这个功能。
总结
要避免出现内存泄露,主动调用remove方法才是正确的。