引言
上一篇文章中提到,子线程不能访问父线程的ThreadLocal变量,InheritableThreadLocal应运而生。InheritableThreadLocal继承自ThreadLocal,并且提供了一个特性,就是子线程可以访问父线程中设置的本地变量。直接看代码:
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
protected T childValue(T parentValue) {
return parentValue;
}
ThreadLocalMap getMap(Thread t) {
//这里变成获取InheritableThreadLocal变量
return t.inheritableThreadLocals;
}
void createMap(Thread t, T firstValue) {
//这里变成创建InheritableThreadLocal变量
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
InheritableThreadLocal继承了ThreadLocal,并且重写了三个方法。后两个方法可见在InheritableThreadLocal的世界中,inheritableThreadLocals替代了threadLocals。那重写的第一个方法有什么用呢?这要从Thread的代码讲起,先看一下Thread类的默认构造函数:
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target,
String name, long stackSize, AccessControlContext acc) {
//获取“当前”线程,也就是创建此线程的线程,也就是父线程
Thread parent = currentThread();
........
//如果父线程的inheritableThreadLocals变量不为null
if (parent.inheritableLocals != null) {
//利用父线程中的inheritableThreadLocals来设置子线程中的inheritableThreadLocals变量
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
this.stackSize = stackSize;
tid = nextThreadID();
}
}
如上代码在创建线程时,在构造函数中会调用init方法,获取父线程,如果父线程的inheritableLocals不为空,则将父线程的inheritableLocals的值赋给子线程。
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
ThreadLocalMap(ThreadLocalMap parentMap)的构造函数内部又做了什么事情呢?
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
//存放复制的结果
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
@SuppressWarnings("unchecked")
//得到父线程中变量对应的key
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if (key != null) {
//重写代码(1)的方法
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}
该构造函数中,将父线程的inheritableLocals成员变量的值复制到了新的ThreadLocalMap对象中,也就是复制到了子线程的本地inheritableLocals变量中。这样就解决了上一篇提到的问题~