从名字我们就可以看到 ThreadLocal 叫做线程变量,意思是 ThreadLocal 中填充的变量属于当前线程,该变量对其他线程而言是隔离的。
ThreadLocal 为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 1;
}
};
ThreadLocal 原理分析
首先ThreadLocal是一个泛型类 ,保证可以接受任何类型的对象 。ThreadLocal内部维护了一个Map , ThreadLocal 实现了一个叫做ThreadLoalMap的静态内部类。ThreadLocalMap 类实现了对应的 get()、set() 方法。
set 方法
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);}
get 方法
public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();}
最终的变量是放在了当前线程的ThreadLocalMap中 ,并不是存在 ThreadLocal 上,ThreadLocal 作为 key。
ThreadLocal 内存泄漏问题
TreadLocalMap 使用 ThreadLocal 的弱引用作为 key,如果一个 ThreadLocal不存在外部强引用时,Key(ThreadLocal)势必会被 GC 回收,这样就会导致ThreadLocalMap 中 key 为 null, 而 value 还存在着强引用,只有 thead 线程退出以后,value 的强引用链条才会断掉。
但如果当前线程再迟迟不结束的话,这些 key 为 null 的 Entry 的 value 就会一直存在一条强引用链:
Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value
永远无法回收,造成内存泄漏。
ThreadLocal 正确的使用方法
每次使用完 ThreadLocal 都调用它的 remove()方法清除数据。