每个线程都用于各自的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,进而清除掉