ThreadLocal是什么?
从名字可以看出ThreadLocal叫做线程本地,即ThreadLocal中填充的变量是属于当前线程的,该变量对其它线程而言是隔离的
源码分析一下ThreadLocal的作用
ThreadLocal<M> tl = new ThreadLocal<>();
tl.set(new M());
tl.remove();
点进去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);
}
获取当前线程,然后将ThreadLocal作为key,你设置的值作为value,放到了一个ThreadLocalMap中.
我们再看一下createMap()方法:
很简单,就是new了一个ThreadLoaclMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
再看一下getMap()方法:
注意,getMap()方法是在Thread类当中,维护了ThreadLocalMap变量ThreadLocal.ThreadLocalMap threadLocals = null;
即每一个线程内部都有一个ThreadLocalMap变量,当你使用threadLocal.set(value)方法时,其实是以ThreadLocal作为key,你设置的值作为value放置在线程内部的ThreadLocalMap中,所以不同线程间的ThreadLocal是隔离的
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
我们再看一下ThreadLocalMap类
Entry类继承了WeakReference类.那么Entry为什么要继承WeakReference弱引用呢?
对于ThreadLocal tl = new ThreadLocal<>();而言,如果Entry不使用弱引用而使用强引用,那么当我把tl=null时,GC依然无法回收ThreadLocal对象,因为再ThreadLocalMap中的Entry依然存在一个引用指向了ThreadLocal,造成对象无法回收,存在内存泄漏.所以需要将Entry设置为弱引用.但是还是存在内存泄漏的问题.因为key是弱引用被回收变成了null,但是value依然存在且无法被回收,所以当threadlocal不再使用时,一定要调用threadLocal.remove()方法