来源:飞天小牛肉
每个线程都有自己的一个 ThreadLocalMap,ThreadLocal 持有的数据就是存在这个 Map 里的(Thread.ThreadLocalMap threadLocals),所以能够实现线程隔离,毕竟每个线程的 ThreadLocalMap 都是不一样的
那如果子线程想要拿到父线程的中的 ThreadLocal 值怎么办呢 ?
比如会有以下的这种代码的实现。在子线程中调用 get 时,我们拿到的 Thread 对象是当前子线程对象,对吧,每个线程都有自己独立的 ThreadLocal,那么当前子线程的 ThreadLocalMap 是 null 的(而父线程,也就是 main 线程中的 ThreadLocalMap 是有数据的),所以我们得到的 value 也是 null
publicclassThreadLocalTest{
privatestaticThreadLocalthreadLocal=newThreadLocal();
publicstaticvoidmain(String[]args)throwsException{
threadLocal.set("芋道源码");
System.out.println("父线程的值:"+threadLocal.get());
newThread(newRunnable(){
@Override
publicvoidrun(){
System.out.println("子线程的值:"+threadLocal.get());
}
}).start();
Thread.sleep(2000);
}
}
结果输出如下:
父线程的值:芋道源码
子线程的值:null
要如何解决这个问题呢?
我们先来从 Thread 类中找找思路:

你会发现,在 ThreadLocalMap threadLocals 的下方,还有一个 ThreadLocalMap 变量 inherittableThreadLocals,inherit 翻译为继承
先看下这个变量的注释:InheritableThreadLocal values pertaining to this thread. This map is maintained by the InheritableThreadLocal class.
oho,这里出现了一个渣渣辉都从未体验过的传新类:InheritableThreadLocal
翻译一下注释,大概就是,如果你使用 InheritableThreadLocal,那么保存的数据都已经不在原来的 ThreadLocal.ThreadLocalMap threadLocals 里面了,而是在一个新的 ThreadLocal.ThreadLocalMap inheritableThreadLocals 变量中了。

所以,如果想让上面那段代码中,子线程能够拿到父线程的 ThreadLocal 值,只需要把 ThreadLocal 声明改为 InheritableThreadLocal 就可以了
下面我们具体来看下 InheritableThreadLocal 是怎么做到父子线程传值的。
首先看下 new Thread 的时候线程都做了些什么 Thread#init()
privatevoidinit(ThreadGroupg,Runnabletarget,Stringname,longstackSize,AccessControlContextacc){
//省略部分代码
Threadparent=currentThread();
if(inheritThreadLocals&&parent.inheritableThreadLocals!=null)
//copy父线程的map,创建一个新的map赋值给当前线程的inheritableThreadLocals
this.inheritableThreadLocals=
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
//省略部分代码
}
核心其实就是上面几句代码,如果你设置了 inheritableThreadLocals 变量,那么 Thread 就会把父线程 ThreadLocal threadLocals 中的所有数据都 copy 到子线程的 InheritableThreadLocal inheritableThreadLocals 中 。
而且,copy 调用的 createInheritedMap 方法其实是一个浅拷贝函数,key 和 value 都是原来的引用地址,这里所谓的 copy 其实就是把一个 Map 中的数据复制到另一个 Map 中:

至此,大致的解释了 InheritableThreadLocal 为什么能解决父子线程传递 Threadlcoal 值的问题了,总结下:
-
在创建
InheritableThreadLocal对象的时候赋值给线程的 t.inheritableThreadLocals 变量 - 在创建新线程的时候会 check 父线程中 t.inheritableThreadLocals 变量是否为 null,如果不为 null 则 copy 一份数据到子线程的 t.inheritableThreadLocals 成员变量中去
-
InheritableThreadLocal重写了 getMap(Thread) 方法,所以 get 的时候,就会从 t.inheritableThreadLocals 中拿到 ThreadLocalMap 对象,从而实现了可以拿到父线程 ThreadLocal 中的值
审核编辑 :李倩
-
数据
+关注
关注
8文章
7314浏览量
93966 -
变量
+关注
关注
0文章
615浏览量
29369 -
线程
+关注
关注
0文章
508浏览量
20757
原文标题:ThreadLocal 父子线程之间该如何传递数据?
文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
ThreadLocal实例应用
LabVIEW多线程编程数据传递教程
鸿蒙原生应用开发-ArkTS语言基础类库多线程TaskPool和Worker的对比(二)
Linux系统中进程与线程之间的关系
QNX消息传递及其在线程间通信的应用
Python、线程和全局解释器锁
ThreadLocal发生内存泄漏的原因
用这4招 优雅的实现Spring Boot异步线程间数据传递
如何使用pthread_barrier_xxx系列函数来实现多线程之间的同步?

ThreadLocal父子线程之间该如何传递数据?
评论