Java版本:8u261。
之前我写过对ThreadLocal源码进行分析的文章,感兴趣的话可以查看《较真儿学源码系列-ThreadLocal(逐行源码带你分析作者思路)》。
InheritableThreadLocal是ThreadLocal的子类,通过前面的分析可知,ThreadLocal只能在同一线程内进行变量的共享,而InheritableThreadLocal不仅可以在同一线程内进行变量的共享,而且可以在父子线程之间进行变量的共享。比如说在父线程a中创建了一个子线程b,那么在a线程中用InheritableThreadLocal包装的变量,在子线程b中也能获取的到。但需要注意的是:InheritableThreadLocal和ThreadLocal一样,在同级线程中依然不能共享变量的值。并且InheritableThreadLocal只能父传子,不能子传父(同时也不是任何时候都能父传子,只有在一开始初始化的时候才会进行数据传递,后面会看到这点)。
public class InheritableThreadLocal extends ThreadLocal {
protected T childValue(T parentValue) {
return parentValue;
}
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
以上便是InheritableThreadLocal的全部源码,可见其只是覆写了ThreadLocal的三个方法而已。而在getMap和createMap方法中可以看到inheritableThreadLocals这个属性,那么这个属性到底是干什么的呢?其实它跟threadLocals属性一样,都是放在Thread类中的属性:
public class Thread implements Runnable {
//...
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
//...
}
正是因为有了inheritableThreadLocals这个属性,就可以让子线程来访问父线程中的本地变量。
在创建线程的时候,会调用到Thread类的init方法:
/**
* Thread:
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
//...
Thread parent = currentThread();
//...
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
/*
将父线程中inheritableThreadLocals的数据初始化到一个新的ThreadLocalMap中,
并赋值给子线程的inheritableThreadLocals
*/
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
//...
}
这里省略了其他不相干逻辑,只需要来看一下inheritableThreadLocals的初始化过程,进一步跟踪第17行代码处:
/**
* ThreadLocal:
*/
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
//parentMap是父线程中的数据
return new ThreadLocalMap(parentMap);
}
/**
* 将父线程中的inheritableThreadLocals复制到一个新的ThreadLocalMap中
* 个人认为这里直接将parentMap返回回去应该也是可以的,但这里重新构建一个
* ThreadLocalMap感觉是为了做一遍清理工作,将Entry为null的哈希槽清理掉
*/
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
//设置子线程的threshold
setThreshold(len);
//初始化子线程的table(因为是在子线程创建的时候调用到这里的,所以不需要判断是否已经初始化,这里一定是未初始化的)
table = new Entry[len];
//遍历父线程中的table
for (int j = 0; j < len; j++) {
//获取其中的Entry
Entry e = parentTable[j];
if (e != null) {
//获取当前槽中的Entry中保存的ThreadLocal
@SuppressWarnings("unchecked")
ThreadLocal
完整的流程如下:
原创不易,未得准许,请勿转载,翻版必究