ThreadLocal的解析在之前文档中有对应的篇章
这里主要解析InheritableThreadLocal
InheritableThreadLocal
由上图可见,InheritableThreadLocal 继承自 ThreadLocal,主要用于将父线程中的值传输到子线程!
主要的三个方法如下:
// 子类独有方法,返回父类的值,parentValue ThreadLocal的泛型
protected T childValue(T parentValue) {
return parentValue;
}
/**重写父类的getMap方法,返回Thread的inheritableThreadLocals引用(默认是返回threadLocals)
*/ t 当前线程
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
/**重写父类的createMap方法,构造的ThreadLocalMap会传到线程的inheritableThreadLocals中
*/
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
代码到这里,无非是与ThreadLocal的ThreadLocalMap引用不一样了,从逻辑上,也做不到得到子线程中父线程的值啊,那究竟是如何获取的?通过查看Thread的构造方法,不难发现在构造Thread对象的时候对父线程的inheritableThreadLocal进行了复制,代码如下:
public class Thread implements Runnable {
//默认人构造方法,会调用init方法进行初使化
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null);
}
//最终会调用到当前这个方法
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name.toCharArray();
// parent为当前线程,也就是调用了new Thread();方法的线程
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
if (security != null) {
g = security.getThreadGroup();
}
if (g == null) {
g = parent.getThreadGroup();
}
}
g.checkAccess();
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
//在这里会继承父线程是否为后台线程的属性还有父线程的优先级
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
//这里是重点,当父线程的inheritableThreadLocals 不为空的时候,
//会调用 ThreadLocal.createInheritedMap方法,
//实际上传入的是父线程的inheritableThreadLocals。原来复制变量的秘密在这里
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
}
因此得出,父线程在调用new Thread()的时候,只要自身的inheritableThreadLocals不为空,就会在生成子线程的时候通过ThreadLocal的createInteritedMap方法传递给子线程,这样就实现了线程间变量的继承与传递。
具体方法代码如下:
public class ThreadLocal<T> {
//根据传入的map,构造一个新的ThreadLocalMap
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
static class ThreadLocalMap {
//这个private的构造方法就是专门给ThreadLocal使用的
private ThreadLocalMap(ThreadLocalMap parentMap) {
//ThreadLocalMap还是用Entry数组来存储对象的
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
//这里是复制parentMap数据的逻辑
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
ThreadLocal key = e.get();
if (key != null) {
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++;
}
}
}
}
}
}
举例如下:
ThreadLocal:
public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
public static void main(String args[]) {
threadLocal.set(new Integer(456));
Thread thread = new MyThread();
thread.start();
System.out.println("main = " + threadLocal.get());
}
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread = " + threadLocal.get());
}
}
InteritableThreadLocal:
public static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<Integer>();
public static void main(String args[]) {
threadLocal.set(new Integer(456));
Thread thread = new MyThread();
thread.start();
System.out.println("main = " + threadLocal.get());
}
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread = " + threadLocal.get());
}
}