代码demo如下:
public static void main(String[] args) throws InterruptedException {
Thread parentParent = new Thread(new Runnable() {
@Override
public void run() {
ThreadLocal threadLocal = new ThreadLocal();
threadLocal.set(1);
InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal();
inheritableThreadLocal.set(2);
new Thread(() -> {
System.out.println("threadLocal=" + threadLocal.get());
System.out.println("inheritableThreadLocal=" + inheritableThreadLocal.get());
}).start();
}
}, "父线程");
parentParent.start();
}
运行结果如下:
可以发现,使用的InheritableThreadLocal对象,是可以让子线程获取到父线程设置到threadLocal中的值的。那么先看看InheritableThreadLocal是什么?可以发现
InheritableThreadLocal是ThreadLocal的子类,如下:
那为什么子线程能够获取到父线程设置在ThreadLocal中的值呢,跟进new Thread()方法中,如下:
继续跟进init方法(),如下:
会发现有个熟悉的参数被设置为了true,继续跟进去,如下:
发现有做个判断,只要参数inheritThreadLocals的值等于true以及父线程中的inheritableThreadLocals不为null,就会调用ThreadLocal.createInheritedMap()方法,把父线程的inheritableThreadLocals作为参传进去,然后把返回的结果再赋值到当前线程的inheritableThreadLocals变量中,接着看看inheritableThreadLocal.get()方法,如下:
会发现其实以上标记出的getMap()方法其实已经被子类InheritableThreadLocal类重写了,所以真实调用的getMap()方法如下:
所以返回的其实是子类的inheritableThreadLocal变量,而该变量其实是由父线程那传递过来再设值的,通过断点验证结果如下:
所以子线程才能拿到2这个结果。
那么值又是怎么设置进父线程的inheritableThreadLocals变量中的呢,跟进inheritableThreadLocal.set()方法,如下:
然后会发现createMap()方法,其实子类InheritableThreadLocal也做了重写,有自己的实现,如下:
所以此时就可以明白值是怎么被设置进线程的inheritableThreadLocals属性。
总结
其实对以上的逻辑进行梳理,可以发现子线程能够获取到父线程的ThreadLocal中的值,是因为子类InheritableThreadLocal重写了一些方法,同时初始化线程时,会根据一定的参数,来决定父线程需不需要把自己的inheritableThreadLocals属性中的值拷贝一份赋值给子线程。