ThreadLocal源码分析
一、关键类分析
1.1ThreadLocal:
ThreadLocal内部有一个ThreadLocalMap静态内部类。
ThreadLocalMap内部类有静态内部类Entry和Entry数组,Entry内部就一个域value用于保存数据,构造方法参数为ThreadLocal和要设置的value。ThreadLocalMap是一个数组实现的map。它的key就是ThreadLocal。
1.2 Thread类分析
thread类里面维护了一个TheadLocal.ThreadLocalMap成员变量。
public class Thread implements Runnable { } |
二、关键方法分析
2.1 get方法分析
①第一步拿到当前的线程,
②拿到当前的线程的ThreadLocalMap成员变量。若当前的ThreadLocalMap对象为空,那么进行初始化。
new ThreadLocalMap(this, firstValue);将当前ThreadLocal对象作为key构造ThreadLocalMap对象。
③将当前的ThreadLocal对象当做key去ThreadLocalMap中取值。
2.2 set方法分析
①第一步拿到当前的线程
②拿到当前的线程的ThreadLocalMap成员变量
③将值设置到key为当前threadlocal对象,value就是传入的参数的ThreadLocalMap中。若ThreadLocalMap对象不存在那么要进行初始化。
2.3 remove方法分析
①拿到当前的线程ThreadLocalMap成员变量
②将ThreadLocalMap数组中当前ThreadLocal对象对应下标索引处的对象设置为null
三、ThreadLocal内存泄露分析
我们看源码发现ThreadLocalMap中的静态内部类Entry继承了WeakReference,即弱引用,也就是说他对ThreadLocal对象的引用是弱引用,当ThreadLocal对象没有外部强引用引用它,那么gc发生后ThreadLocal对象将会回收,那么ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,一直存在一条强引用链,hread Ref -> Thread -> ThreaLocalMap -> Entry -> value,永远无法回收,造成内存泄露。
public class ThreadLocal<T> { public T get() { ①第一步拿到当前的线程 Thread t = Thread.currentThread(); ②拿到当前的线程的ThreadLocalMap成员变量 ThreadLocalMap map = getMap(t); if (map != null) { //若threadlocalmap非空,那么根据当前的threadlocal对象找到值 ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { T result = (T)e.value; return result; } } //若threadlocalmap为空,那么进行初始化 return setInitialValue(); } //返回线程的ThreadLocalMap类型的成员变量threadLocals ThreadLocalMap getMap(Thread t) { return t.threadLocals; } private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else //将当前ThreadLocal对象作为key构造ThreadLocalMap对象。 createMap(t, value); return value; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } static class ThreadLocalMap { private static final int INITIAL_CAPACITY = 16; private Entry[] table; static class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } } public void set(T value) { ①第一步拿到当前的线程 Thread t = Thread.currentThread(); ②拿到当前的线程的ThreadLocalMap成员变量 ThreadLocalMap map = getMap(t); ③将值设置到key为当前threadlocal对象,value就是传入的参数的ThreadLocalMap中。若ThreadLocalMap对象不存在那么要进行初始化。 if (map != null) map.set(this, value); else createMap(t, value); } public void remove() { //拿到当前线程的ThreadLocalMap成员变量 ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) //将ThreadLocalMap数组中当前ThreadLocal对象对应下标索引处的对象设置为null m.remove(this); } private void remove(ThreadLocal<?> key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } } } |