java.lang.ThreadLocal源码分析
ThreadLocal类提供线程本地变量,为变量在每个线程创建一个副本,每个线程可以访问自己内部的副本变量。
比如,有这样一个需求,需要为每个线程创建一个独一无二的标识,这个标识在第一次调用ThreadId.get()的时候生成,在随后的调用中不会再改变。
public class ThreadId { private static final AtomicInteger nextId = new AtomicInteger(0); private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return nextId.getAndIncrement(); } }; public static int get() { return threadId.get(); } }
类声明:
public class ThreadLocal<T> {}
实例变量和相关的一个方法:
//用于ThreadLocalMap private final int threadLocalHashCode = nextHashCode(); //下一个hash code,从0开始 private static AtomicInteger nextHashCode = new AtomicInteger(); //hash增量 private static final int HASH_INCREMENT = 0x61c88647; //在获取下一个hash code private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); }
构造方法:
public ThreadLocal() {}
重要的操作:
//线程本地变量的初始化方法,访问修饰符为protected是为了让程序员可以覆盖这个方法,默认是返回null,也就是说默认的线程本地变量值为null protected T initialValue() { return null; }
get操作
//获取当前线程的本地变量 public T get() { Thread t = Thread.currentThread();//得到当前的线程 ThreadLocalMap map = getMap(t);//根据当前线程获得一个ThreadLocalMap if (map != null) {//如果不为空 ThreadLocalMap.Entry e = map.getEntry(this);//根据当前对象获得Entry if (e != null) {//如果本地变量存在,返回值 @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } //否则调用setInitialValue方法 return setInitialValue(); }
getMap方法
//返回当前线程的threadLocals变量 ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
threadLocals的声明
//其实就是一个ThreadLocalMap类型的变量 ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocalMap
//ThreadLocalMap里有Entry内部类,用于存放键值对 static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } .....以下省略 }
setInitialValue方法
private T setInitialValue() { T value = initialValue();//调用initialValue方法,初始化本地变量的值,如果不覆盖该方法,返回null Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);//根据当前线程获取ThreadLocalMap if (map != null)//如果map不为空 map.set(this, value);//设置键值对 else createMap(t, value);//否则创建map return value; }
createMap方法
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
至此可以知道ThreadLocal如何为每个线程创建变量副本了,每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,存储以ThreadLocal为键,本地线程变量为值的键值对。
remove操作
//先获取当前线程的ThreadLocalMap,然后删除当前ThreadLocal对象 public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }