场景
主要用在多线程场景里,把某个变量设置在线程中,不能被其他线程访问到,保证变量线程安全。如:session管理 ,事务管理,日志输出等等。
源码分析
ThreadLocal 主要提供 有无参数构造方法、set、get、remove方法。无参构造方法中没有代码,说明new的时候没有逻辑。主要看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);
}
先获取当前线程对象,再创建ThreadLocalMap。注意看createMap方法中把ThreadLocalMap对象绑在了线程对象的变量上了。这里才是变量隔离的根本原因,可以看出ThreadLocal本省就像一个工具类。ThreadLocalMap 就是存放数据的地方,类似map,实现类是继承WeakReference的Entry类,WeakReference代表弱应用对象,主要把key进行弱引用,value是强引用的。
get方法、remove方法比较简单。
使用对象关系图:
弱引用
一些博客可能理解不太正确,key弱引用为了value能够被GC回收,否则回收不了,防止内存溢出。
其实key弱引用和value没有关系,由上图可以分析出 主要为了GC能够回收threadLocal对象,前提是threadLocal没有被其他地方引用。threadLocal可以被多次new的,如果不设置弱引用的话,会一直被线程对象引用造成内存泄漏。
这里注意下如果threadLocal被回收那么ThreadLocalMap 中就会出现key 为null的Entry。如果不做remove()方法,value 永远无法被GC 回收,这个时候就也可能会产生内存泄露,前提线程对象一直存在。所以value对象能不能被回收最终要看有么有调用remove方法的和弱引用没有关系。
还有调用set,get,remove方法都会清空key 为null的Entry的对象,也是保证value能够被回收。
个人理解
- 在实际开发应用中通常吧theadLocal在程序启动的时候设置成final static ,所以这里的弱引用其实没有效果,不会被回收的。(弱应用只有面试会被问到)
- 为了安全起见用完一定要调用remove方法,才能保证value被回收,如果线程被共用的话会拿到旧数据。