为每个线程保存一个变量副本 先看java.lang.ThreadLocal#set方法
public void set(T value) {
Thread t = Thread.currentThread(); //获取当前运行的线程
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue); //当前线程的java.lang.Thread#threadLocals被初始化,this时当前threadLoacl对象
}
非常简单,就是获取ThreadLocalMap对象,然后去set,接下来看看java.lang.ThreadLocal.ThreadLocalMap#set
private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table; //弱引用,垃圾回收时会被释放
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);//hash
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value); //存到tab中
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
可以看到值真正存到java.lang.ThreadLocal.ThreadLocalMap#table中,而table是一个java.lang.ThreadLocal.ThreadLocalMap.Entry对象
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
可以看到Entry是持有ThreadLocal的一个弱引用,这意味着当垃圾回收时,Entry的k没有其他强引用的时候就会被回收,那么就无法根据获取到v,而v又没有被释放,就会造成内存泄漏