🧠 一、什么是 ThreadLocal

  • ThreadLocal 是 Java 提供的一种 线程本地变量机制

  • 每个线程都维护一份自己的副本;

  • 它不用于多个线程共享变量,而是用于每个线程独立维护自己的变量副本

  • 常用于:用户上下文、数据库连接、格式化对象(如 SimpleDateFormat)、日志跟踪等场景。


🚀 二、ThreadLocal 的基本用法

ThreadLocal<String> local = new ThreadLocal<>();
local.set("hello");      // 设置当前线程的副本
String val = local.get(); // 获取当前线程的副本
local.remove();           // 手动删除,防止内存泄漏

每个线程访问的是 自己的变量副本,彼此隔离。


🧱 三、ThreadThreadLocalThreadLocalMap 三者关系图

Thread (线程对象)└── ThreadLocalMap (每个线程独有的 map)└── Entry[] 数组├── key:ThreadLocal 对象(弱引用)└── value:真正的变量值

✅ 总结对应关系:

角色说明
Thread每个线程都有一个 ThreadLocalMap
ThreadLocal作为 key 存在于 ThreadLocalMap 中,指向当前线程的副本
ThreadLocalMapThread 内部的属性,负责存储每个 ThreadLocal 对应的数据

🎯 四、为什么 ThreadLocalMap 的 key 是 弱引用

这个想要了解更详细可以看博主的另一篇博客:ThreadLocal--ThreadLocal 竟可能导致内存泄漏?看看 ThreadLocalMap 的弱引用机制-CSDN博客

✅ Java 源码:

static class Entry extends WeakReference<ThreadLocal<?>> {Object value;
}

✅ 原因:防止内存泄漏(重点)

  • 如果 ThreadLocal强引用

    • 即使我们不再使用 ThreadLocal,它依然会作为 key 强引用存在,永远不会被 GC;

    • 而且 ThreadLocalMap 属于 ThreadThread 不结束就不会释放内存;

    • 久而久之,value 也无法回收,造成 内存泄漏

✅ 如果是 弱引用

  • 当开发者不再持有 ThreadLocal 引用时,它会被 GC 回收;

  • GC 后 ThreadLocalMap 中 key 为 null;

  • 如果调用 ThreadLocal.get() / set(),会清除掉这些 stale entry(陈旧数据);

  • ✅ 避免内存泄漏。


💣 五、ThreadLocal 内存泄漏陷阱

  • 问题场景:

    • 线程池中线程长时间不销毁;

    • ThreadLocal 被 GC 回收,但 ThreadLocalMap 的 value 还存在;

    • 如果不调用 .remove(),value 永远不会清理;

  • 解决方式:

    • ✅ 使用完后调用 ThreadLocal.remove() 清理;

    • ✅ 或者用 try-finally 包装使用逻辑:

private static final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));public void parseDate(String dateStr) {try {formatter.get().parse(dateStr);} finally {formatter.remove(); // 手动清除,避免内存泄漏}
}

🧰 六、ThreadLocalMap 的实现细节

  • 本质上是一个自定义的哈希表:

    • 数组结构 + 开放寻址法(冲突后线性探测)

  • 不是 HashMap,也不是 ConcurrentHashMap

  • 数组大小默认 16,按需扩容(最多 2^30)


🛠 七、常用方法详解

方法说明
set(T value)设置当前线程副本中的值
get()获取当前线程副本中的值
remove()删除当前线程副本中的值
withInitial(Supplier)构造带默认初始值的 ThreadLocal


✅ 示例:使用默认初始值的 ThreadLocal

ThreadLocal<Integer> counter = ThreadLocal.withInitial(() -> 0);public void increment() {counter.set(counter.get() + 1);
}

🌟 八、InheritableThreadLocal:子线程继承父线程值

InheritableThreadLocal<String> local = new InheritableThreadLocal<>();
local.set("父线程值");new Thread(() -> {System.out.println(local.get()); // 子线程能读取父线程设置的值
}).start();

适合:父线程传递上下文,如用户ID、请求ID 等。


🧭 九、实际应用场景

场景示例
✅ 用户上下文登录后存放用户信息:ThreadLocal<User>
✅ DateFormatSimpleDateFormat 非线程安全,放入 ThreadLocal
✅ 数据源切换动态数据源管理,存放在 ThreadLocal
✅ Trace ID日志链路追踪,全链路唯一 ID 存 ThreadLocal
✅ Spring事务/安全Spring 的 TransactionSynchronizationManagerSecurityContextHolder 都用到了 ThreadLocal

📌 十、总结

项目内容
本质每个线程一个变量副本
原理每个线程有一个 ThreadLocalMap
结构key 为弱引用的 ThreadLocal,value 为副本值
弱引用原因防止内存泄漏,GC 后 key=null 自动清理
使用建议用完及时调用 remove()
延伸功能InheritableThreadLocal 实现值传递
应用场景用户信息、日期格式化、日志追踪、数据库连接等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/90843.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/90843.shtml
英文地址,请注明出处:http://en.pswp.cn/web/90843.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AWS云S3+Glue+EMRonEC2+ReadShift

Amazon S3&#xff08;Amazon Simple Storage Service&#xff09;即亚马逊简单存储服务&#xff0c;是 AWS&#xff08;Amazon Web Services&#xff09;提供的一种对象存储服务&#xff0c;在大数据领域被广泛使用。以下是关于它的详细介绍&#xff1a;基本概念Amazon S3 主要…

OpenLayers 综合案例-轨迹回放

看过的知识不等于学会。唯有用心总结、系统记录&#xff0c;并通过温故知新反复实践&#xff0c;才能真正掌握一二 作为一名摸爬滚打三年的前端开发&#xff0c;开源社区给了我饭碗&#xff0c;我也将所学的知识体系回馈给大家&#xff0c;助你少走弯路&#xff01; OpenLayers…

语音自动生成PPT、思维导图、会议纪要、笔记、大纲、导读等

一、需要用到录音工具&#xff0c;手机端工具&#xff1a;讯飞听见二、需要用到的工具通义&#xff1a;https://www.tongyi.com/discover上传录音&#xff0c;描述一下&#xff0c;让直接给生成PPT就行&#xff0c;点生成就可以生成ppt&#xff0c;对PPT进行导出就行 三、除了生…

【MySQL】脚本化快速搭建跨平台、可定制的MySQL数据库

冗长的废话就省略了&#xff0c;大家看到这篇博客&#xff0c;效果如标题所示&#xff0c;我将提供完整的脚本&#xff0c;并用 「保姆级」的详细步骤&#xff0c;给你提供一个快速搭建跨平台、可定制的 MySQL环境的解决方案。保证无论你是 Linux 服务器管理员、macOS 开发者&a…

MAC包头、IP包头 、UDP包头中的长度含义是啥?三者之间有啥区别?

以太网帧、IP包及TCP与UDP的报文格式 下面用通俗技术的方式详细解释&#xff1a; 1. MAC包头&#xff08;以太网帧头&#xff09;中的长度 字段名称&#xff1a;EtherType/Length位置&#xff1a;以太网帧头的第13、14字节含义&#xff1a; 如果值小于等于1500&#xff08;0x0…

Multiscale Structure Guided Diffusion for Image Deblurring 论文阅读

基于多尺度结构引导扩散模型的图像去模糊 摘要 扩散概率模型&#xff08;Diffusion Probabilistic Models, DPMs&#xff09;最近被用于图像去模糊&#xff0c;其被表述为一个以模糊输入为条件的图像条件生成过程&#xff0c;将高斯噪声映射到高质量图像。当在成对的域内数据上…

git 提交时排除一个或多个文件

前言 在提交文件时&#xff0c;总是有一些文件是不需要提交的&#xff0c;比如机器上的配置文件&#xff0c;日志文件等等&#xff0c;所以在提交时就需要排除这些文件&#xff1b; 第一种方案 git add file1 file2 比如我新添加了3个文件&#xff1a; file1.txt file2.txt fil…

OpenCV 入门:基础图像操作

在计算机视觉领域&#xff0c;OpenCV 无疑是最受欢迎的开源库之一。它由 Intel 公司俄罗斯团队发起&#xff0c;如今已成为处理图像和视频的强大工具。本文我会介绍OpenCV 的基础知识&#xff0c;从图像的读写显示到实时视频流处理&#xff0c;迈出计算机视觉的第一步。 目录 …

大语言模型 LLM 通过 Excel 知识库 增强日志分析,根因分析能力的技术方案(3):使用云平台最小外部依赖方案

文章大纲 1 方案总览(与官方文档映射) 2 环境准备(一步完成) 3 数据层(零代码迁移 Excel → BigQuery 或 SQLite) 4 函数声明(JSON Schema 与官方示例一致) 5 Cloud Function(**最小外部依赖**) 6 客户端调用(对齐官方 Python 示例) 7 Token 与性能对比(官方计费口…

C++高效实现轨迹规划、自动泊车、RTS游戏、战术迂回包抄、空中轨迹、手术机器人、KD树

C++ 算法汇总 基于C++的城市道路场景 以下是基于C++的城市道路场景中车辆紧急变道轨迹生成的实现方法和示例代码。内容涵盖轨迹规划算法、数学建模及代码实现,适用于自动驾驶或驾驶辅助系统开发。 基于多项式曲线的轨迹生成 采用五次多项式(Quintic Polynomial)生成平滑…

电动汽车转向系统及其工作原理

电动汽车的转向系统作为电动汽车的一个关键系统&#xff0c;与燃油车的转向系统有着较大差异。电动汽车的转向系统主要分为 电动助力转向&#xff08;EPS, Electric Power Steering&#xff09; 、电动液压助力转向系统&#xff08;EHPS, Electro-Hydraulic Power Steering&…

TCP/IP 体系结构网络接口层的原理

TCP/IP 网络接口层详解 网络接口层&#xff08;Network Interface Layer&#xff09;是 TCP/IP 模型的最底层&#xff08;对应 OSI 模型的物理层 数据链路层&#xff09;&#xff0c;负责在物理网络中传输原始比特流&#xff0c;实现相邻设备之间的可靠数据传输。核心功能物理…

笔记本键盘的启用和禁用

管理员 打开 CMD&#xff1a;这一步要求以管理员权限打开命令提示符&#xff08;Command Prompt&#xff09;。在Windows系统中&#xff0c;可以通过搜索“cmd”&#xff0c;然后右键选择“以管理员身份运行”来实现。sc config i8042prt start disabled (关闭笔记本键盘)&…

vue3的一些浅显用法

1/ 父页面调用子页面相关需要在父页面引用 <FieldUserForm ref"userFormRef" success"handleUserFormSuccess" />其中 FieldUserForm 是子页面 success"handleUserFormSuccess" 是子页面成功后回调方法 父页面 实现 handleUserFormSucces…

C语言习题讲解-第五讲-循环编程练习等

C语言习题讲解-第五讲-循环编程练习等1. 关于一维数组描述不正确的是&#xff1a;( )2. 关于一维数组初始化&#xff0c;下面哪个定义是错误的&#xff1f;&#xff08; &#xff09;3. 定义了一维 int 型数组 a[10] 后&#xff0c;下面错误的引用是&#xff1a;&#xff08; &…

MongoDB索引及其原理

目录 索引原理 索引类型 单键索引 组合索引 特性索引 唯一索引 稀疏索引 部分索引 TTL索引 多键索引 文本索引 地理空间索引 哈希索引 总结 MongoDB 索引执行计划 索引原理 MongoDB索引的背后的原理和MySQL中的索引原理是差不多的,都是使用B数来对数据进行管理…

学习嵌入式的第三十三天-数据结构-(2025.7.25)服务器/多客户端模型

服务器/多客户端模型循环服务器 while(1){ accept(); recv(); } 适用于简单任务&#xff0c;如基础Web服务器&#xff0c;但无法处理并发请求。并发服务器 通过thread或fork实现多任务处理。需注意子进程/线程的资源回收&#xff0c;避免内存泄漏。多路IO模型服务器 使用select…

【Canvas与标牌】优质资产六角星标牌

【成图】【代码】<!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>优质资产六角星标记 Draft1</title><style type"text/cs…

扫雷游戏开发教程:从零打造精美像素扫雷

完整源码在本文结尾处一、游戏概述 扫雷是一款经典的益智游戏&#xff0c;玩家需要在不触发地雷的情况下揭开所有安全格子。本教程将带你从零开始开发一个具有精美界面和动画效果的扫雷游戏&#xff0c;包含难度选择、棋盘大小调整等高级功能。 二、游戏核心功能 三种难度级别&…

Linux驱动开发笔记(五)——设备树(上)

内容详见《【正点原子】I.MX6U嵌入式Linux驱动开发指南》四十三章 开发板&#xff1a;imx6ull mini 虚拟机&#xff1a;VMware17 ubuntu&#xff1a;ubuntu20.04 一、什么是设备树 视频&#xff1a;第6.1讲 Linux设备树详解-什么是设备树&#xff1f;_哔哩哔哩_bilibili 对…