为什么一个线程中有两个ThreadLocalMap?

本来是想介绍Scoped Values的,但是牵扯到ThreadLocalInheritableThreadLocal,所以先来介绍这两个技术,同时解决一个问题:为什么一个线程中有两个ThreadLocalMap?

先贴出Thread类中的源码方便理解问题:

先给出结论:当我们使用ThreadLocal来共享值时用的是线程中的threadLocals属性,当我们使用InheritableThreadLocal来共享值时用的是inheritableThreadLocals属性。

先聊聊ThreadLocal

一个线程 串行执行多个方法时,如果需要在这多个方法中共享变量时,就可以通过ThreadLocal来进行传递。但并不是每个线程都需要一个ThreadLocal对象,而是多个线程可以共用一个ThreadLocal对象,比如看下面代码:

变量NAME就是一个ThreadLocal对象,如果此时有线程1、线程2同时来调用方法a(),并传入不同的参数,那么这两个线程使用的就是同一个ThreadLocal对象,在a()方法中给NAME设置不同的值,然后这两个线程在执行b()、c()方法时,从NAME中也将拿到不同的值。

思考:ThreadLocal对象的set()和get()方法是如何区分不同线程保存所设置的值的呢?

答案呼之欲出,通过获取到执行set()和get()方法的当前线程 自然就能区分不同线程,然后使用Map 来保存所设置的值就可以了,所以set()的源码如下,其中就获取了当前线程:

但是上面这段代码有误导性,会让人觉得当前线程就是Map的key,但是我们继续看内层set()方法的源码:

源码中,getMap(t)方法会获取当前线程对象的threadLocals属性,从而得到一个ThreadLocalMap对象,然后把当前正在执行set()方法的ThreadLocal对象(源码中的this)作为key,set的值作为value,存入ThreadLocalMap,所以Map的key是ThreadLocal对象。

而对于ThreadLocal的get()方法就比较容易理解了,直接看源码:

get()方法的核心流程:先拿到当前线程对象,从线程中获取ThreadLocalMap,最后将当前在调用get()方法的ThreadLocal对象作为key从ThreadLocalMap中获取value返回。

对于ThreadLocal再做一次总结:每个线程中有一个 threadLocals属性对应的ThreadLocalMap,线程在执行ThreadLocal对象的set()、get()方法时,会把ThreadLocal对象作为key并利用这个ThreadLocalMap设置值或获取值

再聊聊InheritableThreadLocal

线程中另外一个属性inheritableThreadLocals也是一个ThreadLocalMap,InheritableThreadLocal类继承了ThreadLocal类,但是InheritableThreadLocal的真正意义是:子线程会继承父线程中的 inheritableThreadLocals对应的ThreadLocalMap,而且是复制一份,也就是子线程中的ThreadLocalMap和父线程中的ThreadLocalMap中的内容一开始是一样的,但是后续的修改将互不影响,注意当我们用InheritableThreadLocal时,线程中的 threadLocals属性就没有作用了。

一段代码就可以看出效果: 当使用ThreadLocal时,以上代码中子线程是获取不到值的,但是如果改成用InheritableThreadLocal则能获取到值。

如果在子线程中修改NAME的值也不会影响父线程:

当调用InheritableThreadLocal的set()方法时,最终会执行到InheritableThreadLocal的getMap()方法: 所以InheritableThreadLocal用的是线程对象中的inheritableThreadLocals属性。

而在new Thread()时,在构造方法里会把父线程中的inheritableThreadLocals的ThreadLocalMap内容复制 给当前子线程的inheritableThreadLocals:

好了,以上就是关于ThreadLocal与InheritableThreadLocal的介绍与分析了,希望大家有收获,那么问题来了:ThreadLocal有哪些缺点呢?为什么JDK21的新特性之一 Scoped Values跟ThreadLocal、InheritableThreadLocal又有关系呢?

关注我,我们下期见。

广告

我准备运营自己的知识星球啦,知识星球以免费答疑、优化简历、讨论技术 为主,另外还能帮助大家提升工作效率快速拿到offer认识更多大牛学习更多技术。

前50名 小伙伴(发文时只有最后10个了),可以免费 加入星球,私信我领取免费链接!

如果您愿意直接付费 加入,那当然也是可以的啦

相关推荐
东风破_2 小时前
danci 2:创建的单词书到底存在哪里?从 Supabase 一路理解 ORM、Drizzle 和 RLS
数据库·后端·node.js
微尘寒风2 小时前
【Git】的安装和使用
java·git
东风破_3 小时前
danci 项目(三):从 JSON 数据到 AI Coding,真实项目里的数据清洗、Prompt 和工程规范
前端·后端·node.js
y = xⁿ3 小时前
DeepSeek Harness 学习日记:关于Agent接口,工具调用的底层实现
android·java·学习
九皇叔叔3 小时前
《MySQL 体系架构详解:Server 层、SQL 执行流程与 InnoDB、MyISAM、MEMORY 存储引擎》
sql·mysql·架构
怕浪猫3 小时前
FDE 最大的浪费不是写出有 bug 的代码,而是漂亮地解决了一个错误的问题
面试·架构·github
东风破_3 小时前
danci 项目(一):从需求到架构,一个单词学习系统为什么会这样设计
前端·后端·node.js
侧耳倾听1113 小时前
jwt使用简介
java·jwt
顶点多余4 小时前
那些在算法中适合巩固的知识点---1
java·前端·算法
AI人工智能+电脑小能手4 小时前
大白话说Java设计模式-46-责任链模式(业务实战篇)
java·设计模式·责任链模式·风控校验·servlet filter·spring interceptor·链式处理