【多线程】ThreadLocal是什么?有哪些使用场景?使用ThreadLocal需要注意些什么?
文章目录
- 前言
- 一、ThreadLocal 是什么?
- 二、有哪些使用场景?
- 三、实现原理
- 四、在线程池中使用 ThreadLocal 为什么可能导致内存泄露呢?
- 五、线程池中,如何正确使用 ThreadLocal?
- 六、ThreadLocal 核心方法
前言
一、ThreadLocal 是什么?
ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。
二、有哪些使用场景?
经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection; 还有 Session管理等问题。
ThreadLocal 使用例子:
public class TestThreadLocal {//线程本地存储变量private static final ThreadLocal<Integer> THREAD_LOCAL_NUM = new ThreadLocal<Integer>() {@Overrideprotected Integer initialValue() {return 0;}};public static void main(String[] args) {for (int i = 0; i < 3; i++) {//启动三个线程Thread t = new Thread() {@Overridepublic void run() {add10ByThreadLocal();}};t.start();}}/*** 线程本地存储变量加 5*/private static void add10ByThreadLocal() {for (int i = 0; i < 5; i++) {Integer n = THREAD_LOCAL_NUM.get();n += 1;THREAD_LOCAL_NUM.set(n);System.out.println(Thread.currentThread().getName() + " : ThreadLocal num=" + n);}}}
打印结果:启动了 3 个线程,每个线程最后都打印到 “ThreadLocal num=5”,而不是 num 一直在累加直到值等于 15
Thread-0 : ThreadLocal num=1
Thread-1 : ThreadLocal num=1
Thread-0 : ThreadLocal num=2
Thread-0 : ThreadLocal num=3
Thread-1 : ThreadLocal num=2
Thread-2 : ThreadLocal num=1
Thread-0 : ThreadLocal num=4
Thread-2 : ThreadLocal num=2
Thread-1 : ThreadLocal num=3
Thread-1 : ThreadLocal num=4
Thread-2 : ThreadLocal num=3
Thread-0 : ThreadLocal num=5
Thread-2 : ThreadLocal num=4
Thread-2 : ThreadLocal num=5
Thread-1 : ThreadLocal num=5
三、实现原理
按照我们第一直觉,感觉 ThreadLocal 内部肯定是有个 Map 结构,key 存了 Thread,value 存了 本地变量 V 的值。每次通过 ThreadLocal 对象的 get() 和 set(T value) 方法获取当前线程里存的本地变量、设置当前线程里的本地变量。

而 JDK 的实现里面这个 Map 是属于 Thread,而非属于 ThreadLocal。ThreadLocal 仅是一个代理工具类,内部并不持有任何与线程相关的数据,所有和线程相关的数据都存储在 Thread 里面。ThreadLocalMap 属于 Thread 也更加合理。
还有一个更加深层次的原因,这样设计不容易产生内存泄露。
ThreadLocal 持有的 Map 会持有 Thread 对象的引用,只要 ThreadLocal 对象存在,那么 Map 中的 Thread 对象就永远不会被回收。ThreadLocal 的生命周期往往比线程要长,所以这种设计方案很容易导致内存泄露。
JDK 的实现中 Thread 持有 ThreadLocalMap,而且 ThreadLocalMap 里对 ThreadLocal 的引用还是弱引用(WeakReference),所以只要 Thread 对象可以被回收,那么 ThreadLocalMap 就能被回收。JDK 的这种实现方案复杂但更安全。

四、在线程池中使用 ThreadLocal 为什么可能导致内存泄露呢?
在线程池中线程的存活时间太长,往往都是和程序同生共死的,这样 Thread 持有的 ThreadLocalMap 一直都不会被回收,再加上 ThreadLocalMap 中的 Entry 对 ThreadLocal 是弱引用(WeakReference),所以只要 ThreadLocal 结束了自己的生命周期是可以被回收掉的。
Entry 中的 Value 是被 Entry 强引用的,即便 value 的生命周期结束了,value 也是无法被回收的,导致内存泄露。
五、线程池中,如何正确使用 ThreadLocal?
在 finally 代码块中手动清理 ThreadLocal 中的 value,调用 ThreadLocal 的 remove()方法。
六、ThreadLocal 核心方法
- 设置 Thread 对应的 Value 值,首次会创建一个 ThreadLocalMap ,添加 ThreadLocal - Value 到 ThreadLocalMap 中,并且绑定 ThreadLocalMap 到当前线程。
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);
}
- 创建 ThreadLocalMap,绑定到当前线程。
void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}
- 通过 ThreadLocalMap 获取当前线程的存储的 Value 值
public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();
}
- 设置 ThreadLocal 的初始化值,未 set(T value) 初次获取 Thread 对应的 Value 值时会调用,即被 setInitialValue 方法调用。需要重写该方法。
protected T initialValue() {return null;
}
- 移除当前线程存储的 Value 值。当 ThreadLocal 不在使用,最好在 finally 语句块中,调用 remove() 方法,释放去 Value 的引用,避免内存泄露。
public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);
}
相关文章:
【多线程】ThreadLocal是什么?有哪些使用场景?使用ThreadLocal需要注意些什么?
文章目录 前言一、ThreadLocal 是什么?二、有哪些使用场景?三、实现原理四、在线程池中使用 ThreadLocal 为什么可能导致内存泄露呢?五、线程池中,如何正确使用 ThreadLocal?六、ThreadLocal 核心方法 前言 一、Threa…...
一种基于动态代理的通用研发提效解决方案
作为一名研发人员,除了业务开发之外,研发提效是一个永恒的话题,而女娲正是这一话题下进行的一次全面的剖析和实践。 作者:张全洪(钝悟) 一、女娲是什么 女娲是业务研发同学(开发、测试、运维)在软件迭代的…...
【vue3】一些关于hooks的使用经验
前言 最近接到了一个需求,隔壁嵌入式部门希望我们用前端解析渲染Kconfig表单。这篇文章用来记录一下本次使用hook pinia vue3的经验 hooks hooks的概念最早是在 React 中听到的,虽然早些时间也写过一点react,但也只是照葫芦画瓢…...
面试系列 - Java 并发容器详解
Java 并发容器是一组用于在多线程环境下安全访问和操作数据的数据结构。它们提供了线程安全的集合和映射,使开发者能够更轻松地处理并发编程问题。 一、Java并发容器 ConcurrentHashMap: 它是一个高效的并发哈希表,支持多线程并发操作而不需…...
使用动态住宅代理还能带来哪些好处?
一、什么是动态住宅代理ip 动态住宅代理是一种代理技术,它利用代理服务器中转用户和目标服务器之间的网络流量,实现用户真实位置的屏蔽。代理提供商会有自己的ip大池子,当你通过代理服务器向网站发送请求时,服务器会从池子中选中…...
笙默考试管理系统-MyExamTest----codemirror(18)
笙默考试管理系统-MyExamTest----codemirror(18) 目录 一、 笙默考试管理系统-MyExamTest----codemirror 二、 笙默考试管理系统-MyExamTest----codemirror 三、 笙默考试管理系统-MyExamTest----codemirror 四、 笙默考试管理系统-MyExamTest---…...
TGA格式文件转材质
今天淘宝上买了一个美女的模型,是blender的源文件,上面说有fbx格式的。我用unity,所以觉得应该可以用。文件内容如下图: FBX文件夹打开后,内容如下图所示,当时就预感到可能没有色彩。 unity打开后果然发现只…...
IP应用场景查询API:深入了解网络用户行为的利器
前言 随着数字时代的不断发展,互联网已经成为人们生活的重要组成部分。而随着越来越多的业务和社交活动迁移到在线平台上,了解和理解网络用户行为变得至关重要。为了满足这个需求,IP 应用场景查询 API 崭露头角,成为深入了解网络…...
docker从零部署jenkins保姆级教程(上)
jenkins,基本是最常用的持续集成工具。在实际的工作中,后端研发一般没有jenkins的操作权限,只有一些查看权限,但是我们的代码是经过这个工具构建出来部署到服务器的,所以我觉着有必要了解一下这个工具的搭建过程以及简…...
2023数模A题——定日镜场的优化问题
A题——定日镜场的优化问题 思路:该题主要考察的几何知识和天文学知识,需要不同角度下的镜面和遮挡情况。 资料获取 问题1: 若将吸收塔建于该圆形定日镜场中心,定日镜尺寸均为 6 m6 m,安装高度均为 4 m,且…...
Container is running beyond memory limits
问题 Hadoop环境中,执行MapReduce程序或者Hive 任务时候,任务执行失败,提示内存不足。 Container is running 337869312B beyond the VIRTUAL’ memory limit.Current usage:295.8 NB of 1 GB physical memoryused;2.4 GB of 2.1 GB virtual…...
Java后端开发面试题——JVM虚拟机篇
目录 什么是程序计数器? 你能给我详细的介绍Java堆吗? 什么是虚拟机栈 1. 垃圾回收是否涉及栈内存? 2. 栈内存分配越大越好吗? 3. 方法内的局部变量是否线程安全? 4.什么情况下会导致栈内存溢出? 5.堆栈的区别…...
SpringMVC增删改查(CRUD)的实现
目录 前言 一、前期准备 1.pom.xml---依赖与插件的导入 2.jdbc.properties---数据库连接 3.log4j2.xml---日志文件 4.spring-mybatis 5.spring-context 6.spring-mvc 二、增删改查的实现 1.model与mapper层的生成 2.biz层 3.工具类 4.controller层 三、测试结果 总…...
智安网络|面临日益增长的安全威胁:云安全和零信任架构的重要性
随着云计算技术的快速发展和广泛应用,云安全和零信任架构变得愈发重要。在数字化时代,云计算技术得到了广泛的应用和推广。企业和组织借助云服务提供商的强大能力,实现了高效、灵活和可扩展的IT基础设施。然而,随着云环境的快速发…...
JVM常用调优策略
1、JVM调优的核心关注指标 调优之前首先我们要知道怎样才算是“优”,不能笼统的说我的程序性能很好,所以就需要有一个具体的指标来衡量性能情况,而在JVM里面衡量性能两个指标分别“吞吐量”和“停顿时间”。 吞吐量:程序运行过程…...
自动化防火墙放行目标域名IP
#!/bin/bash # 设置要获取IP地址的域名 domain"yourdomain.com"# 获取域名的IP地址 new_ip$(dig short A $domain)# 移除之前添加放行的IP地址(通过备注找它的编号) rule_number$(iptables -L INPUT -n --line-numbers -v | awk -v domain&quo…...
12.2RAC环境从RAC转为单机模式的问题处理
近期,在某用户的测试环境,需要将RAC转为单机模式,然后进行数据恢复;一开始只是将数据库软件通过make -f ins_rdbms.mk rac_off 和 make -f ins_rdbms.mk ioracle关闭RAC模式;然后在启动数据库(sqlplus / a…...
Docker 中 jdk8容器里无法使用 JDK 的 jmap 等命令的问题
一、问题描述 项目部署在 CentOS 服务器上。项目偶尔会出现无响应的情况,这时理所当然要上去用 JDK 相关命令看看堆栈和GC等信息了。 进入 Java 程序所在容器:docekr-compose exec api bash,进入到 api 容器的 bash 终端。 jps 打印 Java …...
typeScript--[es6class类实现继承]
一.js中实现继承 // js实现继承 // 父类 function Father(name) {this.name namethis.say function () {console.log(this.name "在唱歌")} } var f new Father("逍遥的码农")// 子类 function Son(name) {Father.call(this, name) } Son.prototype …...
解决eclipse的报错:Must declare a named package because this compilation
刚安装完成eclipse, 创建类的时候报错 报错信息如下: 原因:新版本的ECLIPSE要求每一个类都必须定义在包里面 解决方法:创建类的时候指定类的名字,如下图:Package 里面填写ch3,表示包名 创建完成…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
[USACO23FEB] Bakery S
题目描述 Bessie 开了一家面包店! 在她的面包店里,Bessie 有一个烤箱,可以在 t C t_C tC 的时间内生产一块饼干或在 t M t_M tM 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC,tM≤109)。由于空间…...
