为了账号安全,请及时绑定邮箱和手机立即绑定

原来 ThreadLocal 还有“继承版”?InheritableThreadLocal 真相揭秘!

标签:
Java JavaScript

原文来自于:https://zha-ge.cn/java/84

原来 ThreadLocal 还有“继承版”?InheritableThreadLocal 真相揭秘!

身为老 Java 程序员,ThreadLocal 早就烂熟于心,可有次聊起多线程变量传递,居然被面试官出了道“你用过 InheritableThreadLocal 吗?”的骚操作。当场脑门一紧:啥?ThreadLocal 还有“亲儿子版”?其实我刚入行业的时候,老觉得:ThreadLocal 不就是让每个线程自个儿玩自个的吗?结果这几年业务越来越离谱,各种异步线程池、请求串联,突然发现真有点东西——

于是,这个“山寨 ThreadLocal”到底是个啥?用起来和老本尊真的一样吗?不啰嗦,咱聊点程序员的心里话。


那次糊涂:变量丢了

有回我在写个用户上下文,登录用户信息放 ThreadLocal,原以为安全得很:

threadLocal.set(userInfo); // 请求线程里塞进去
// ……业务处理……

结果写了个异步队列,子线程要调这个信息。嗯,结果好嘛,直接空指针打脸。原来线程变量还真没“遗传”到新开的线程里?(难道咱 ThreadLocal 这么绝情吗?)

当时的内心 OS 可以用一句话总结:

  • “线程隔离,太特么彻底了!”

后来 Google 一下,发现江湖上居然流传着 InheritableThreadLocal 这么个“带血缘”的东西!


踩坑瞬间

说干就干,把 ThreadLocal 换成 InheritableThreadLocal,心想“变量终于能随儿子线程流淌了”。

private static final InheritableThreadLocal<User> userCtx =
    new InheritableThreadLocal<>();
// 父线程塞进去
userCtx.set(user);
// 子线程再读
User u = userCtx.get();
  • 如果你用 new Thread() 真·新线程跑,嗬,还真能拿到。
  • 但是你如果用线程池,刺激的事情发生了,变量压根没同步进来,还是 NULL!

又查查官方文档,才发现 InheritableThreadLocal 只有在线程刚创建、start 的时候,才会把父线程的变量复制一份给子线程(其实是 clone,不是引用)。
线程池里的线程是池化的,起都起好了,不会每次复制。

你瞅瞅,这玩意简直比前任还迷惑:

  • 有时传,有时不传,情感极不稳定……

一点小总结:到底咋回事

核心点其实很简单:

特性 ThreadLocal InheritableThreadLocal
变量范围 当前线程 当前线程 + 新建子线程(仅new Thread)
线程池行为 线程独立 线程独立,老线程不自动复制
数据可传递性 不可跨线程 只在 new 出来、刚启动的子线程里会变“遗传”

要注意:

  • 线程池基本不适用。因为线程池的线程通常不会因为你要变量才新创建,导致值不会自动同步过去。
  • 变量其实是内容浅拷贝,改了子线程的值,父线程没影响,反之亦然。

经验启示

写给下一位壮士的几点建议:

  1. 别乱用 InheritableThreadLocal,尤其别觉着可以在任何多线程环境自动搞定上下文传递。
  2. 要跨线程、线程池传递变量?老老实实用阿里开源的 TransmittableThreadLocal 或自己写逻辑显式传递!
  3. 真怕“泄露”——上下文别忘记移除,不然内存胖死你。
  4. 面试官问 InheritableThreadLocal 干嘛用的时候,记住这句金句:“适合短命线程,不适合线程池!”

写完这些随手抬头,才发现,被各路“ThreadLocal 儿孙”虐了一圈,只有自己最靠谱。切记:
上下文传播,Java 能帮的那点事,图省事你就输了。

好啦,今天的“ThreadLocal DNA 鉴定”就聊到这。放下代码,喝口水,远望天花板,继续在 Bug 的路上奋勇前行吧。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消