ThreadLocal
GC 之后 key 是否为 null?
不一定。
(1)当使用new ThreadLocal<>().set(s);
定义threadlocal时,没有在栈中声明一个变量指向他,那他就是只被弱引用。在gc后,那这个threadlocal就会被回收,key为null,value还一直在,就会造成内存泄漏,所以注意在使用完threadlocal后一定要调用remove方法,避免因为key为null造成内存泄漏。
(2)当使用ThreadLocal<object> threadLocal = new ThreadLocal<>();
方式定义时,相当于栈中存在一个变量threadLocal指向这个对象,形成强引用,即使在entry中,作为key是弱引用,但是在栈中一直有一个名为“threadLocal”的变量在指向他,存在强引用,所以这种情况下不会导致key为空。但是只要该变量所在的方法执行完之后,threadLocal变量消失,只剩一个弱引用,那么key也还是会被清理变成null。
为什么key使用弱引用?
如果使用强引用,当ThreadLocal
对象的引用(强引用)被回收了,ThreadLocalMap
本身依然还持有ThreadLocal
的强引用,如果没有手动删除这个key ,则ThreadLocal
不会被回收,所以只要当前线程不消亡,ThreadLocalMap
引用的那些对象就不会被回收, 可以认为这导致Entry
内存泄漏。
ThreadLocalMap扩容机制
在ThreadLocalMap.set()
方法的最后,如果执行完启发式清理工作后,未清理到任何数据,且当前散列数组中Entry
的数量已经达到了列表的扩容阈值(len*2/3)
,就开始执行rehash()
逻辑:这里首先是会进行探测式清理工作,从table
的起始位置往后清理,table
中可能有一些key
为null
的Entry
数据被清理掉,此时通过判断size >