本文最后更新于156 天前,其中的信息可能已经过时,如有错误请发送邮件到3368129372@qq.com
组成
ThreadLocal->ThreadLocalMap
->Entry1(key(ThreadLocal类型), value),Entry1(key(ThreadLocal类型), value)... ...
ThreadLocalMap类似于哈希map,线性探测法解决冲突,实现为
static class ThreadLocalMap {
private static final int INITIAL_CAPACITY = 16;
private Entry[] table;
private int size = 0;
private int threshold;
private void setThreshold(int len) {
this.threshold = len * 2 / 3;
}
private static int nextIndex(int i, int len) {
return i + 1 < len ? i + 1 : 0;
}
private static int prevIndex(int i, int len) {
return i - 1 >= 0 ? i - 1 : len - 1;
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
this.table = new Entry[16];
int i = firstKey.threadLocalHashCode & 15;
this.table[i] = new Entry(firstKey, firstValue);
this.size = 1;
this.setThreshold(16);
}
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
this.setThreshold(len);
this.table = new Entry[len];
Entry[] var4 = parentTable;
int var5 = parentTable.length;
for(int var6 = 0; var6 < var5; ++var6) {
Entry e = var4[var6];
if (e != null) {
ThreadLocal<Object> key = (ThreadLocal)e.get();
if (key != null) {
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h;
for(h = key.threadLocalHashCode & len - 1; this.table[h] != null; h = nextIndex(h, len)) {
}
this.table[h] = c;
++this.size;
}
}
}
}
内存泄漏问题
-
ThreadLocal的实现为
static class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); this.value = v; } }
可见key(即ThreadLocal)对象为弱引用。因为Thread能到达ThreadLocal,而Thread可能被线程池复用而长时间不销毁。因此需要改为弱引用,只存在弱引用时只要GC就被回收。
注:一般ThreadLocal作为某个类的成员变量而被强引用,这个类销毁时说明强引用消失,马上被GC) - 为什么value不设成弱引用呢?因为value不会被作为成员变量而强引用,直接回收会导致ThreadLocal还在但是对应的值已经消失了!!!
- 在调用get方法时会检测对应的ThreadLocal(key)是否还存在,无则回收value值。
- 内存泄漏的情况:未使用remove(),且set()后未get()回收value,且线程被复用,Thread对象一直存在时。