介绍
inheritableThreadLocals是一个线程变量,继承于ThreadLocal。
重写了3个方法,特别是下面的两个方法。
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
/**
* Create the map associated with a ThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the table.
*/
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
从上述可知,它在获取Map集合的时候用的线程成员变量inheritableThreadLocals。 而父类ThreadLocal用的Map集合是线程成员变量threadLocals.
这两个变量都是属于线程成员变量,初始值为空。
/* 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;
这两个成员变量的区别在于,threadLocals 不能被子线程继承,inheritableThreadLocals 可以被子线程继承。这一点可以在创建线程的时候看到。
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
公开访问的两个创建线程的方法中都调用了init方法,关键代码如下:
....
this.target = target;
setPriority(priority);
if (inheritThreadLocals && 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();
如果parent.inheritableThreadLocals != null,那么执行 this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);以此方式将线程变量集合Map传递给子线程。
坑
从上述可知,集合Map是通过线程创建过程传递的,当业务中存在异步调用时注意了:
1. 如果子线程直接由父线程创建后再使用,那么子线程可以得到父线程的集合Map,父线程中通过inheritableThreadLocals.set()的值也可以传递到子线程。
2. 如果子线程不是由当前父线程直接创建的,而是已经存在的,那么无法传递。比如线程池使用时,线程的循环使用过程中就存在这种情况,子线程得不到父线程通过inheritableThreadLocals.set()的值,因为子线程是被其他线程创建后再循环使用的。因此线程池中不建议使用inheritableThreadLocals, 直接new Thread(Runnable);
3. remove()方法,父子线程都使用了inheritableThreadLocals,那么谁需要调用remove(),从而避免内存泄漏?都需要调用。