ThreadLocal不支持继承性,即在子线程中无法使用父线程的ThreadLocal,因此提供了InheritableThreadLocal来实现在子线程中也能使用父线程的ThreadLocal。
在使用InheritableThreadLocal时,应该注意,父线程中对InheritableThreadLocal变量的赋值要先于对子线程的定义,例如
Runnable runnable = () ->{
System.out.println("thread threadLocal is " + threadLocal.get());
System.out.println("thread inheritableThreadLocal is : " + inheritableThreadLocal.get());
};
Thread thread = new Thread(runnable);
threadLocal.set("threadLocal is only found in main thread");
inheritableThreadLocal.set("inheritableThreadLocal can be found in both thread and main thread!");
上述方式中,子线程同样访问不到父线程中的inheritableThreadLocal,但是换成如下方式则可以访问到。
Runnable runnable = () ->{
System.out.println("thread threadLocal is " + threadLocal.get());
System.out.println("thread inheritableThreadLocal is : " + inheritableThreadLocal.get());
};
threadLocal.set("threadLocal is only found in main thread");
inheritableThreadLocal.set("inheritableThreadLocal can be found in both thread and main thread!");
Thread thread = new Thread(runnable);
为什么会出现这样的情况?看一下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();
//...
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();
}
在线程中的ThreadLocal默认值null,只有在调用ThreadLocal的set方法时,线程才会创建ThreadLocal,inheritableThreadLocal继承自ThreadLocal,所以也是同样的方式创建的。
如果我们在父线程中,对threadLocal.set()晚于子线程的定义Thread thread = new Thread(runnable),那么在创建子线程的init()方法中可以看到,Thread parent = currentThread();获取父线程,由于此时父线程对threadLocal的赋值在子线程的定义之后,因此理所当然的parent.inheritableThreadLocals == null 成立,所以子线程中也就没有InheritableThreadLocal了,也就无法在子线程中使用父线程的InheritableThreadLocal。