前言
最近项目中经常用到了ThreadLocal,所以仔细研究一下这个类,以备以后复习。
threadLocals和inheritableThreadLocals
这个类是依附于Thread而存在的,所以我们先来讨论线程类中的两个变量源码如下
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
inheritableThreadLocals
我们先看inheritableThreadLocals的作用,由于inheritableThreadLocals在线程创建的时候初始化,所以我们看线程创建的init方法 相关部分如下
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
由上可以看出在每个线程初始化的时候线程会将当前线程的父级线程中inheritableThreadLocals的数据拷贝一份到自己线程的inheritableThreadLocals中。
因此可以通过将数据存入inheritableThreadLocals中来将数据传入子线程。
父级线程和子单程对inheritableThreadLocals的操作互不影响。
threadLocals
我们再来看threadLocals这是Java中线程本地变量存储的在第一次操作的时候(set/get)进行初始化代码如下
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//get如果找不到对应map就会去初始化一个对象并且往里放一个null值
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();
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
//下面为初始化代码
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//创建一个entry数组其中entry的key只能是ThreadLocal类实例的引用,值为设置的值。
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); //对引用取模 然后确定在table中的索引位置
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY); //计算扩容阀值
}
以上可见threadLocals是依附于当前线程中的一个存储线程变量的map,不会被其他线程访问,当前线程独有。
总结
threadLocals 存储线程变量 当前线程独有 只有当前线程能访问。
inheritableThreadLocals 存储可被继承的线程变量,线程生成之后
父线程的线程变量和子线程的线程变量也相互独立