ThreadLocal核心原理—底层实现与Thread关联机制
一、前言在上一篇文章中我们已经掌握了 ThreadLocal 的基本使用知道它能为每个线程提供独立的变量副本实现无锁化的线程安全。但你是否有过这样的疑问ThreadLocal 是如何做到线程隔离的线程和 ThreadLocal 之间到底是什么关系本文将带你深入 ThreadLocal 的源码拆解它的底层实现逻辑彻底搞懂线程隔离的核心原理。二、核心思想ThreadLocal 实现线程隔离的核心思想是“数据存储在线程内部”而非 ThreadLocal 自身存储数据。每个 Thread 线程对象中都持有一个 ThreadLocalMap 类型的成员变量当我们通过 ThreadLocal 的 set() 方法存储数据时实际上是将数据存入当前线程的 ThreadLocalMap 中调用 get() 方法时则是从当前线程的 ThreadLocalMap 中取出数据。三、问题本质分析ThreadLocal 的核心问题本质是“如何建立 Thread、ThreadLocal、数据副本三者之间的关联关系”。如果让 ThreadLocal 直接存储所有线程的数据副本会导致 ThreadLocal 持有大量线程的引用容易引发内存泄漏且无法高效区分不同线程的数据。如果让线程直接存储数据又无法与多个 ThreadLocal 变量进行绑定。因此JDK 设计了ThreadLocalMap 作为中间载体让每个线程持有一个 ThreadLocalMap以 ThreadLocal 实例作为 Key以数据副本作为 Value完美解决了三者的关联问题。四、核心逻辑1. Thread 与 ThreadLocalMap 的关联首先我们查看 java.lang.Thread 类的源码会发现它定义了两个与 ThreadLocal 相关的成员变量/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals null; /* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */ ThreadLocal.ThreadLocalMap inheritableThreadLocals null;threadLocals存储当前线程的 ThreadLocal 数据副本默认值为 null 由 ThreadLocal 类负责维护。inheritableThreadLocals用于父子线程间的数据传递由 InheritableThreadLocal 类维护。核心结论 每个线程都有自己专属的 ThreadLocalMapThreadLocal 只是一个 “工具类”负责向 Thread 的 ThreadLocalMap 中存取数据。2. ThreadLocal 的 set() 方法核心逻辑ThreadLocal 的 set() 方法是实现数据存储的关键源码如下基于 JDK 8public void set(T value) { // 1. 获取当前线程对象 Thread t Thread.currentThread(); // 2. 获取当前线程的 ThreadLocalMap ThreadLocalMap map getMap(t); // 3. 如果 ThreadLocalMap 已存在直接存入数据否则创建新的 ThreadLocalMap if (map ! null) map.set(this, value); else createMap(t, value); } // 获取当前线程的 ThreadLocalMap ThreadLocalMap getMap(Thread t) { return t.threadLocals; } // 为当前线程创建 ThreadLocalMap并初始化第一个键值对 void createMap(Thread t, T firstValue) { t.threadLocals new ThreadLocalMap(this, firstValue); }逻辑拆解 调用 Thread.currentThread() 获取当前执行的线程对象 t 。通过 getMap(t) 方法拿到线程 t 的 threadLocals 成员变量即 ThreadLocalMap。如果 ThreadLocalMap 已经存在就以 当前 ThreadLocal 实例作为 Key 以要存储的值 value 作为 Value存入 Map 中。如果 ThreadLocalMap 不存在则调用 createMap() 方法为线程 t 创建一个新的 ThreadLocalMap并初始化第一个键值对。3. ThreadLocal 的 get() 方法核心逻辑get() 方法用于从当前线程的 ThreadLocalMap 中获取数据源码如下public T get() { // 1. 获取当前线程对象 Thread t Thread.currentThread(); // 2. 获取当前线程的 ThreadLocalMap ThreadLocalMap map getMap(t); // 3. 如果 ThreadLocalMap 存在则查找对应的 Value if (map ! null) { ThreadLocalMap.Entry e map.getEntry(this); if (e ! null) { SuppressWarnings(unchecked) T result (T)e.value; return result; } } // 4. 如果 ThreadLocalMap 不存在或没有找到对应的 Value则初始化 return setInitialValue(); } // 初始化 ThreadLocal 的值 private T setInitialValue() { T value initialValue(); Thread t Thread.currentThread(); ThreadLocalMap map getMap(t); if (map ! null) map.set(this, value); else createMap(t, value); return value; }逻辑拆解 同样先获取当前线程对象和对应的 ThreadLocalMap。如果 ThreadLocalMap 存在则以当前 ThreadLocal 实例为 Key查找对应的 Entry 键值对。如果找到 Entry 则返回对应的 Value否则调用 setInitialValue() 方法。setInitialValue()方法会调用我们重写的 initialValue() 方法获取初始值然后创建 ThreadLocalMap 并存入初始值。五、ThreadLocal 存取数据流程为了让大家更清晰地理解整个过程我们将 ThreadLocal 存取数据的流程拆解为4个步骤步骤 1线程启动ThreadLocalMap 初始化为 null当一个线程比如 Thread-0 启动时它的 threadLocals 成员变量默认是 null 此时 ThreadLocalMap 尚未创建。步骤 2调用 ThreadLocal.set ()触发 ThreadLocalMap 创建当我们在 Thread-0 中调用 threadLocal.set(data) 时获取当前线程 Thread-0 。发现 Thread-0 的 threadLocals 为 null 于是调用 createMap() 方法。createMap()方法会创建一个新的 ThreadLocalMap 对象并将 threadLocal 作为 Key、 data 作为 Value存入这个 Map 中。最后将这个 ThreadLocalMap 对象赋值给 Thread-0 的 threadLocals 成员变量。步骤 3同线程再次调用 set ()直接存入新数据如果在 Thread-0 中再次调用 threadLocal.set(newData) 获取 Thread-0 的 ThreadLocalMap此时已存在。直接以 threadLocal 为 Key将 Value 更新为 newData 。步骤 4调用 ThreadLocal.get ()从当前线程的 Map 中取值当调用 threadLocal.get() 时获取当前线程 Thread-0 的 ThreadLocalMap。以 threadLocal 为 Key 查找对应的 Value返回给调用方。步骤 5线程内其他 ThreadLocal 变量独立存储如果在 Thread-0 中还有另一个 ThreadLocal 变量 threadLocal2 调用 threadLocal2.set(data2) 时同样获取 Thread-0 的 ThreadLocalMap。以 threadLocal2 为 Key、 data2 为 Value存入同一个 ThreadLocalMap 中。此时 Thread-0 的 ThreadLocalMap 中存在两个键值对Key 分别是 threadLocal 和 threadLocal2 彼此互不干扰。六、图解 Thread、ThreadLocal、ThreadLocalMap 的关系为了更直观地理解三者的关联我们用一张图来总结核心结论 每个线程的 ThreadLocalMap 是独立的不同线程的 ThreadLocalMap 互不干扰。同一个线程的 ThreadLocalMap 可以存储多个 ThreadLocal 变量的数据Key 是 ThreadLocal 实例Value 是对应的数据副本。七、总结本文通过源码分析彻底搞懂了 ThreadLocal 的核心原理线程隔离的本质数据存储在 线程自身的 ThreadLocalMap 中而非 ThreadLocal 中。三者关系Thread 持有 ThreadLocalMapThreadLocal 作为 Key数据副本作为 Value。核心方法逻辑set() 和 get() 方法的核心都是 先获取当前线程的 ThreadLocalMap再进行存取操作 。理解了 ThreadLocal 与 Thread 的关联机制后下一个关键问题来了ThreadLocalMap 的底层结构是怎样的它和 HashMap 有什么区别这些问题将在下一篇文章中详细讲解。

相关新闻

基于Multisim的多功能分频电路设计与仿真实现

基于Multisim的多功能分频电路设计与仿真实现

1. 从零开始理解分频电路 分频电路在数字电子系统中扮演着重要角色,就像音乐播放器里的节拍器,能够将原始时钟信号按照特定比例降低频率。我第一次接触分频电路是在大学电子设计课上,当时用面包板搭建的电路总是出现信号抖动问题&#xff0c…

2026/5/17 3:08:43 阅读更多 →
Docker 27存储卷动态扩容不求人:手写50行Go插件接管volume生命周期,已通过CNCF兼容性认证

Docker 27存储卷动态扩容不求人:手写50行Go插件接管volume生命周期,已通过CNCF兼容性认证

第一章:Docker 27存储卷动态扩容的演进与挑战 Docker 27(即 Docker v27.x,代指 2024 年发布的重大更新系列)首次将存储卷(Volume)的在线动态扩容能力纳入官方运行时核心支持范畴。此前,用户需依…

2026/7/3 3:38:59 阅读更多 →
ESP32智能家居毕业设计从零入门:选型、实现与避坑指南

ESP32智能家居毕业设计从零入门:选型、实现与避坑指南

ESP32智能家居毕业设计从零入门:选型、实现与避坑指南 摘要:许多高校学生在毕业设计中选择ESP32构建智能家居系统,却常因缺乏嵌入式开发经验陷入通信不稳定、功耗过高或OTA失败等困境。本文面向新手,系统梳理基于ESP32的Wi-Fi/蓝牙…

2026/5/17 3:08:36 阅读更多 →

最新新闻

基于混沌系统与DNA编码的图像加密算法原理与Matlab实现

基于混沌系统与DNA编码的图像加密算法原理与Matlab实现

1. 项目概述:当混沌遇上DNA,图像加密的新思路最近在复现和优化一些经典的图像加密算法,发现将Logistic映射和Chen超混沌系统结合起来,再引入DNA分块编码,是一条非常有意思的技术路线。这不仅仅是两个混沌系统的简单堆叠…

2026/7/5 20:08:17 阅读更多 →
LaTeX-Workshop环境变量深度解析:高级配置与性能优化实战

LaTeX-Workshop环境变量深度解析:高级配置与性能优化实战

LaTeX-Workshop环境变量深度解析:高级配置与性能优化实战 【免费下载链接】LaTeX-Workshop Boost LaTeX typesetting efficiency with preview, compile, autocomplete, colorize, and more. 项目地址: https://gitcode.com/gh_mirrors/la/LaTeX-Workshop 作…

2026/7/5 20:04:16 阅读更多 →
CANN特征向量检索指南

CANN特征向量检索指南

特征向量检索(FV) 【免费下载链接】docs 该仓库用于维护cann公共文档 项目地址: https://gitcode.com/cann/docs 基本原理 该部分主要实现了对特征检索的功能验证,生成随机底库,随机生成特征数据进行特征检索(…

2026/7/5 20:04:16 阅读更多 →
5个核心场景解锁:NBTExplorer可视化编辑器让Minecraft数据编辑变得如此简单

5个核心场景解锁:NBTExplorer可视化编辑器让Minecraft数据编辑变得如此简单

5个核心场景解锁:NBTExplorer可视化编辑器让Minecraft数据编辑变得如此简单 【免费下载链接】NBTExplorer A graphical NBT editor for all Minecraft NBT data sources 项目地址: https://gitcode.com/gh_mirrors/nb/NBTExplorer 你是否曾经因为看不懂Minec…

2026/7/5 19:58:15 阅读更多 →
终极黑苹果配置革命:智能硬件识别与OpenCore自动化配置

终极黑苹果配置革命:智能硬件识别与OpenCore自动化配置

终极黑苹果配置革命:智能硬件识别与OpenCore自动化配置 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 在传统黑苹果配置过程中&#xff0…

2026/7/5 19:58:15 阅读更多 →
D-Link DCS摄像头CVE-2020-25078漏洞剖析与批量检测脚本实现

D-Link DCS摄像头CVE-2020-25078漏洞剖析与批量检测脚本实现

1. 项目概述:一次对D-Link DCS监控设备信息泄露漏洞的深度剖析最近在整理网络设备安全审计案例时,一个老生常谈但又屡见不鲜的漏洞类型再次引起了我的注意——硬编码或未授权访问导致的信息泄露。D-Link DCS系列网络监控摄像头爆出的CVE-2020-25078漏洞&…

2026/7/5 19:58:15 阅读更多 →

日新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻