ThreadLocal
ThreadLocal
的原理
-
每个线程Thread内部有一个类型为**
ThreadLocalMap
,名为threadLocals
的成员变量。该成员变量类似HashMap, 其中 key为我们定义的ThreadLocal
变量的this引用,value则为我们set时候的值,**所以说是每个线程的本地变量是存到到线程自己的内存变量threadLocals
里面的-
ThreadLocal.ThreadLocalMap threadLocals = null; //Thread类
-
-
例如**set()**方法中
a. 首先获取当前线程;然后获取该线程的**ThreadLocalMap
**成员变量;
b. 如果threadLocals
为null,说明是第一次调用set方法,则创建当前线程的threadLocals
变量
c. 如果不为null,则把value放入当前线程的内存变量threadLocals
中。 key就是当前ThreadLocal
的实例对象引用,value是通过set方法传递的值
-
set()
-
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) //this 是ThreadLocal, 即new出来的tl map.set(this, value); else createMap(t, value); }
-
ThreadLocal的内存溢出
- Thread中有一个map,就是ThreadLocalMap,ThreadLocalMap的key是ThreadLocal,值是我们自己设定的。ThreadLocal是一个弱引用,当为null时,会被当成垃圾回收
- ThreadLocal是null了,也就是要被垃圾回收器回收了,但是此时我们的ThreadLocalMap生命周期和Thread的一样,它不会回收,这时候就出现了一个现象。那就是ThreadLocalMap的key没了,但是value还在,这就造成了内存泄漏。
- **解决:**使用完ThreadLocal之后,应该调用remove方法。因为调用remove方法,就会删除对应线程的
threadLocals
中的本地变量 - 使用了线程池,可以达到“线程复用”的效果。但是归还线程之前记得清除ThreadLocalMap,要不然再取出该线程的时候,ThreadLocal变量还会存在。这就不仅仅是内存泄露的问题了,整个业务逻辑都可能会出错。
ThreadLocal的应用场景
- 线程间数据隔离
- 进行事务操作,用于存储线程事务信息。
- 数据库连接,Session会话管理。
- 在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。