每个线程实例都具备有一个ThreadLocal的ThreadLocalMap,在Thread中定义如下
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
它以ThreadLocal的实例为key,以需要set的值为value,它与普通Map最大的区别就是它的Entry是针对ThreadLocal实例弱引用的,当外部ThreadLocal引用为空时,GC就将其回收掉了,在ThreadLocalMap内的表现就是出现了一个key为null的Entry。所以当前线程长时间不结束,而大量的ThreadLocal废弃时,就会发生内存泄露。
而ThreadLocalMap内部也有一些处理方式将其回收掉而且必须在set新值的时候
1. 当hash算法得到的table index刚好是一个废弃的ThreadLocal时,则会清除掉或替换掉
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
2.在新建Entry且刚好没有命中废弃的ThreadLocal时,则会调用cleanSomeSlots遍历清理废弃的ThreadLocal
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
3.扩容的时候,如上,rehash的时候也会遍历清理
4.线程结束,ThreadLocalMap也就随之清理了。
另外,ThreadLocal并不是用来解决共享对象多线程访问问题的,是用来保持各个线程都能保持各自独立的对象的
浙公网安备 33010602011771号