public class Thread implements Runnable { /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
}
public class ThreadLocal<T> { public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } }
结合上面的图看,ThreadLocal是线程(Thread)的私有变量,所以不同线程之间的threadLocal变量是隔离出来的,只能同一个线程取。Thread下面有一个成员变量threadlocals指向着ThreadLocalMap(可以看成一个hashMap),Entry对象里面的key、value分别是ThreadLocal和对应的value值。
ThreadLocal容易发生内存泄漏,当线程没有销毁,一直存在的时候,随着时间的延长,ThreadLocal里面的Entry会越来越多。(根可达性算法GC,线程(Thread)下的属性变量threadLocls无法被回收)
原来 ThreadLocal
的 ThreadLocalMap
里面存的每一个 Entry 是一个 WeakReference
,WeakReference
会在 GC 的时候进行回收,回收的其实是 key
,也就是弱引用的 referent
, 然后 ThreadLocal
会在 set 和 get 的时候对 key 为空的 value 进行删除,所以这样就完美解决了当前线程生命周期不结束的时候,不同的 ThreadLocal
不停的追加到当前线程上面,导致内存溢出。
所以使用完毕不用后应该调用ThreadLocal.remove() 移除entry,防止应为value的强引用导致无法被gc回收。
使用方法 pulic static ThreadLocal<String> str = new ThreadLocal<>(); str.set("aaa"); str.get("aaa"); str.remove();