Redian新闻
>
ThreadLocal 父子线程之间该如何传递数据?

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

公众号新闻

点击上方“芋道源码”,选择“设为星标

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:飞天小牛肉


每个线程都有自己的一个 ThreadLocalMap,ThreadLocal 持有的数据就是存在这个 Map 里的(Thread.ThreadLocalMap threadLocals),所以能够实现线程隔离,毕竟每个线程的 ThreadLocalMap 都是不一样的

如果子线程想要拿到父线程的中的 ThreadLocal 值怎么办呢

比如会有以下的这种代码的实现。在子线程中调用 get 时,我们拿到的 Thread 对象是当前子线程对象,对吧,每个线程都有自己独立的 ThreadLocal,那么当前子线程的 ThreadLocalMap 是 null 的(而父线程,也就是 main 线程中的 ThreadLocalMap 是有数据的),所以我们得到的 value 也是 null

public class ThreadLocalTest {
 private static ThreadLocal<String> threadLocal = new ThreadLocal<String>();

    public static void main(String[] args) throws  Exception{
        threadLocal.set("芋道源码");
        System.out.println("父线程的值:"+ threadLocal.get());
        new Thread(new Runnable() {
            @Override
            public void run() {
                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()

private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) {
 // 省略部分代码
 Thread parent = 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 值的问题了,总结下:

  1. 在创建 InheritableThreadLocal 对象的时候赋值给线程的 t.inheritableThreadLocals 变量
  2. 在创建新线程的时候会 check 父线程中 t.inheritableThreadLocals 变量是否为 null,如果不为 null 则 copy 一份数据到子线程的 t.inheritableThreadLocals 成员变量中去
  3. InheritableThreadLocal 重写了 getMap(Thread) 方法,所以 get 的时候,就会从 t.inheritableThreadLocals 中拿到 ThreadLocalMap 对象,从而实现了可以拿到父线程 ThreadLocal 中的值


欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。

谢谢支持哟 (*^__^*)

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
观点丨许勤华:Follow Green Development with Chinese-style Modernization白酒行业的品牌资产沉淀样本:毛铺如何传递「和而不同」的价值主张?见证历史?据传国内45亿条快递数据泄露如何在 Ubuntu 和其他 Linux 下安装 IDLE Python IDE | Linux 中国中国标准证明美国新冠只死了6万世界上最变态的父母日本啊,日本(十三)利休之死潮牌THRASHER火焰卫衣,仅凭一个Logo就帅炸你!【Locker Room】LOL联赛?篮球全明星?Lockerroom有什么新活?给家里买东西,父亲不领情:父子之间的沟通为何这样拧巴?JUC多线程:CountDownLatch、CyclicBarrier、Semaphore 同步器原理YOLOv8来啦 | 详细解读YOLOv8的改进模块!YOLOv5官方出品YOLOv8,必卷!Out with the old, in with the new. JuniorCoach is here for you面试官:数据库日期类型字段,需要兼容不同数据库,应该如何选择?【Locker Room】春季了,你不运动一下吗?快来lockerroom 看看吧!ThreadLocal 搭配线程池使用造成内存泄漏的原因和解决方案At Last, a Spring Festival Family Reunion After Three Years卅载积淀,老字号律所如何传承再出发?[歪解] the grass is always greener on the other side老了也要玩得大百年潮涌·学长风华丨詹天佑:中国铁路工程之父BOSE SoundLink Color Bluetooth® Speaker IIPostdoctoral Research Associate in Immunology and Infectious Dis突发!多国限制中国访客入境!英国停止发布新冠数据?Want To Use the Toilet? Throw Away Your Trash First.Looking for Closure, a Grandson Built a Ghost in the MachineMy Three Years of the PigSpringBoot 使用线程池如何控制主线程和子线程的事务新冠后的中风读完 RocketMQ 源码,我学会了如何优雅的创建线程乔伊斯的这句“love loves to love love”,到底啥意思?Are Audiences Still Interested in ‘Three Body’ Adaptations?用这4招 优雅的实现Spring Boot 异步线程间数据传递活久见!拟IPO企业被现场检查竟吓到删数据?"𝙇𝙚𝙖𝙙 𝙏𝙝𝙚 𝘾𝙝𝙖𝙧𝙜𝙚"广告#创译挑战
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。