ThreadLocal
解释
- ThreadLocal对象实质为ThreadLocalMap的key
- ThreadLocalMap是每个Thread对象中包含的一个Map容器
- ThreadLocalMap中存放的entry继承自WeakReference(弱引用)
每个线程都用于各自的ThreadLocalMap,该容器的使用天生具有多线程访问下的互斥性。
使用场景
- 对象的跨层传递
- 线程间的数据隔离
- 事务操作(Spring的@Transactional)
- 数据库连接管理,session会话管理
源码阅读
public T get() {
Thread t = Thread.currentThread(); // 1.先获取当前线程
ThreadLocalMap map = getMap(t); // 2.获取当前线程的ThreadLocalMap
if (map != null) {
// 3.以当前ThreadLocal对象为key获取map中的值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread(); // 1.获取当前对象
ThreadLocalMap map = getMap(t); // 2.获取当前对象的ThreadLocalMap
// 3.将当前ThreadLocal对象和value组成K-V存入ThreadLocalMap
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
内存泄露问题
内存泄漏:不会使用到的内存空间无法被回收
为什么要引入弱引用:若key使用强引用,回收时ThreadLocal对象和value对象都不会被回收(若不手动清除的话);若使用弱引用ThreadLocal会被gc回收,但value需要手动清除
泄漏原因:由于ThreadLocal的生命周期和Thread一样长,若不手动删除对应的key就会导致内存泄漏
正确使用方式:
- 每次使用完手动remove()清除
- 将ThreadLocal变量定义成private static,这样就一直存在ThreadLocal强引用,这样就能在任何时候通过ThreadLocal的弱引用访问到Entry的value,进而清除掉