ThreadLocal
- ThreadLocal
- ThreadLocalMap
- get
- set
- remove
- 内存泄漏
- key用强/弱引用
- entry继承了弱引用
ThreadLocal
-
一个对象的所有线程会共享其全局变量——>线程不安全
解决方式:
方式一:同步机制,加锁(时间换空间)
方式二:ThreadLocal在每个线程中都创建了一个变量的副本,线程各自访问自己的副本变量,则不存在变量共享问题。(空间换时间)变量与线程的关系private static,所以ThreadLocal与线程的关系private static
eg:session -
同一个线程内多个函数/组件间公共变量传递复杂,降低了多模块间的耦合度。关联线程和线程上下文
ThreadLocalMap
每一个thread都有一个threadLocalMap变量,key=threadLocal value=值
(一个thread可以有多个threadLocal)
public class Thread implements Runnable {//存储与此线程相关的threadLocal,值由threadLocal维护ThreadLocal.ThreadLocalMap threadLocals;
}
jdk1.7的实现方式为每一个threadLocal都有一个threadLocalMap变量,key=threadID value=值
- 储存的entry减少,之前由thread数量决定,现在由threadLocal决定
- thread销毁对应的threadLocalMap也销毁。threadLocalMap的生命周期=线程的生命周期,内存使用减少
get

private T get(Thread t) {ThreadLocalMap map = getMap(t);if (map != null) {if (map == ThreadLocalMap.NOT_SUPPORTED) {return initialValue();} else {//根据ThreadLocalHash计算index,取得Entry ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T) e.value;return result;}}}return setInitialValue(t);
}private T setInitialValue(Thread t) {T value = initialValue();ThreadLocalMap map = getMap(t);assert map != ThreadLocalMap.NOT_SUPPORTED;if (map != null) {map.set(this, value);} else {createMap(t, value);}if (this instanceof TerminatingThreadLocal<?> ttl) {TerminatingThreadLocal.register(ttl);}return value;
}
set

private void set(Thread t, T value) {ThreadLocalMap map = getMap(t);if (map == ThreadLocalMap.NOT_SUPPORTED) {throw new UnsupportedOperationException();}if (map != null) {map.set(this, value);} else {createMap(t, value);}
}//存入值
private void set(ThreadLocal<?> key, Object value) {// We don't use a fast path as with get() because it is at// least as common to use set() to create new entries as// it is to replace existing ones, in which case, a fast// path would fail more often than not.Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {if (e.refersTo(key)) {e.value = value;return;}if (e.refersTo(null)) {replaceStaleEntry(key, value, i);return;}}tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();
}//初始化map
void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}
remove
private void remove(Thread t) {ThreadLocalMap m = getMap(t);if (m != null && m != ThreadLocalMap.NOT_SUPPORTED) {m.remove(this);}
}
内存泄漏
引用链:threadRef->thread->threadLocalMap<threadLocal,value>->entry->value
弱引用:如果这个对象只存在弱引用,那么在下一次GC时会被清理。
ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用。所以如果 ThreadLocal 没有被外部强引用,在GC时ThreadLocal 会被清理掉,ThreadLocalMap中使用这个 ThreadLocal 的 key 也会被设为null。由于value 是强引用,不会被清理,依然存在,就会出现 key 为 null 的 value,value无法访问。在map中value为强引用不会被清除,直到map被清除。然而由于threadLocalMap的生命周期=线程,线程池通常采取线程复用的方法,所以线程池中的线程很难结束。所以value可能一直无法回收。

key用强/弱引用
- key用强引用:引用ThreadLocal的对象被回收了,但threadLocalMap中还有threadLocal的强引用,若未手动删除,threadLocal不会被回收,导致entry内存泄漏
- key用弱引用:引用ThreadLocal的对象被回收了,但threadLocalMap中还有threadLocal的弱引用,即使未手动删除,threadLocal也会被回收,导致value内存泄漏
- 结论:若未手动删除key,都会导致内存泄漏。强引用threadLocal不会被回收,弱引用value。 内存泄漏与强/弱引用无关,根本原因在于threadLocalMap的生命周期=线程。
解决方式:用完threadLocal,调用remove清除无用的entry,由于Entry继承了弱引用类,会在下次GC时被JVM回收。get(),set(),remove(),会顺便移除key=null的entry
entry继承了弱引用
public class ThreadLocal<T> {static class ThreadLocalMap {private Entry[] table;//轻量级map,桶中存entry而非entry链表//Entry 继承弱引用static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}}
}
相关文章:
ThreadLocal
ThreadLocalThreadLocalMapgetsetremove内存泄漏key用强/弱引用entry继承了弱引用ThreadLocal 一个对象的所有线程会共享其全局变量——>线程不安全 解决方式: 方式一:同步机制,加锁(时间换空间) 方式二:…...
Java基础:JDK7-时间Date
JDK7以前时间相关类 1.Date Date date new Date(); , sout(date)得到的是现在所处位置的时间 Date date new Date(0L); , sout(date)得到的是时间原点也就是1970年1月1日08:00(东八区). date.setTime(1000L); sout(date)得到的是时间原点后一秒钟的时间 long time date.g…...
什么是IP地址?
IP协议中还有一个非常重要的内容,那就是给因特网上的每台计算机和其它设备都规定了一种地址,叫做“IP 地址”。由于有这种地址,才保证了用户在连网的计算机上操作时,能够高效而且方便地从千千万万台计算机中选出自己所需的对象来。…...
4年经验之谈,什么是接口测试?怎样做接口测试?
一、什么是接口?【文末学习资源分享】赶紧嫖!冲!!!! 接口测试主要用于外部系统与系统之间以及内部各个子系统之间的交互点,定义特定的交互点,然后通过这些交互点来,通过…...
普通指针扫盲
一、什么是指针 C语言里,变量存放在内存中,而内存其实就是一组有序字节组成的数组,每个字节有唯一的内存地址。 CPU 通过内存寻址对存储在内存中的某个指定数据对象的地址进行定位。这里,数据对象是指存储在内存 中的一个指定数据…...
深度学习笔记:神经网络权重确定初始值方法
神经网络权重不可为相同的值,比如都为0,因为如果这样网络正向传播输出和反向传播结果对于各权重都完全一样,导致设置多个权重和设一个权重毫无区别。我们需要使用随机数作为网络权重 实验程序 在以下实验中,我们使用5层神经网络…...
关于 python 的异常使用说明 (python 的文件和异常)
文章目录异常1. 处理异常 ZeroDivisionError 异常2. 使用 try-except 代码块3. 使用异常避免崩溃4. else 代码块5. 处理 FileNotFoundError 异常6. 分析文本7. 失败时一声不吭异常 pyhong 使用被异常成为异常的特殊对象来管理程序执行期间发生的错误。 每当发生让 python 不知所…...
Spark RDD持久化
RDD Cache缓存 RDD通过Cache或者Persist方法将前面的计算结果缓存,默认情况下会把数据以序列化的形式缓存在JVM的堆内存中。但是并不是这两个方法被调用时立即缓存,而是触发后面的action时,该RDD将会被缓存在计算节点的内存中,并供…...
【Linux】Linux系统安装Python3和pip3
1.说明 一般来说Linux会自带Python环境,可能是Python3或者Python2,可能有pip也可能没有pip,所以有时候需要自己安装指定的Python版本。Linux系统下的安装方式都大同小异,基本上都是下载安装包然后编译一下,再创建好软…...
用java进行base64加密
首先定义一组密钥,加密和解密使用同一组密钥private final String key "hahahahahaha";也可以随机生成密钥/*** 生成随机密钥* param keySize 密钥大小推荐128 256* return* throws NoSuchAlgorithmException*/public static String generateSecret(int keySize) th…...
torch函数合集
torch.tensor() 原型:torch.tensor(data, dtypeNone, deviceNone, requires_gradFalse) 功能:其中data可以是:list,tuple,NumPy,ndarray等其他类型,torch.tensor会从data中的数据部分做拷贝(而不是直接引用),根据原始数据类型生成相应类型的torch.Tenso…...
AcWing算法提高课-3.1.2信使
宣传一下算法提高课整理 <— CSDN个人主页:更好的阅读体验 <— 题目传送门点这里 题目描述 战争时期,前线有 nnn 个哨所,每个哨所可能会与其他若干个哨所之间有通信联系。 信使负责在哨所之间传递信息,当然,…...
Paddle OCR Win 11下的安装和简单使用教程
Paddle OCR Win 11下的安装和简单使用教程 对于中文的识别,可以考虑直接使用Paddle OCR,识别准确率和部署都相对比较方便。 环境搭建 目前PaddlePaddle 发布到v2.4,先下载paddlepaddle,再下载paddleocr。根据自己设备操作系统进…...
杂谈:数组index问题和对象key问题
面试题一: var arr [1, 2, 3, 4] 问:arr[1] ?; arr[1] ?答:arr[1] 2; arr[1] 2 这里可以再分为两个问题: 1、数组赋值 var arr [1, 2, 3, 4]arr[1] 10; // 数字场景 arr[10] 1; // 字符串场景 arr[a] 1; // 字符串…...
三天Golang快速入门—Slice切片
三天Golang快速入门—Slice切片Slice切片切片原理切片遍历append函数操作切片append添加append追加多个切片中删除元素切片合并string和slice的联系Slice切片 切片原理 由三个部分构成,指针、长度、容量指针:指向slice第一个元素对应的数组元素的地址长…...
腾讯会议演示者视图/演讲者视图
前言 使用腾讯会议共享PPT时,腾讯会议支持共享用户使用演示者视图/演讲者视图,而会议其他成员可以看到正常的放映视图。下面以Win10系统和Office为例,介绍使用步骤。值得一提的是,该方法同时适用于单显示屏和多显示屏。 腾讯会议…...
【C++】类与对象(一)
文章目录1、面向过程和面向对象初步认识2、类的引入3、类的定义4、类的访问限定符5、类的作用域6、类的实例化7、计算类对象的大小8、this指针9、 C语言和C实现Stack的对比1、面向过程和面向对象初步认识 C语言是面向过程的,关注的是过程,分析出求解问题…...
JavaScript基本语法
本文提到的绝大多数语法都是与Java不同的语法,相同的就不会赘述了.JavaScript的三种引入方式内部js<body><script>alert(hello);</script> </body>行内js<body><div onclick"alert(hello)">这是一个div 点击一下试试</div>…...
OpenCV4.x图像处理实例-道路车辆检测(基于背景消减法)
通过背景消减进行道路车辆检测 文章目录 通过背景消减进行道路车辆检测1、车辆检测思路介绍2、BackgroundSubtractorMOG23、车辆检测实现在本文中,将介绍如何使用简单但有效的背景-前景减法方法执行车辆检测等任务。本文将使用 OpenCV 中使用背景-前景减法和轮廓检测,以及如何…...
pwnlab通关流程
pwnlab通关 关于文件包含,环境变量劫持的一个靶场 信息收集 靶机ip:192.168.112.133 开放端口 根据开放的端口信息决定从80web端口入手 目录信息 在images和upload路径存在目录遍历,config.php被渲染无法查看,upload.php需…...
旧电脑秒变云服务器:用Proxmox VE打造家庭虚拟化实验室(ZFS配置优化版)
旧电脑秒变云服务器:用Proxmox VE打造家庭虚拟化实验室(ZFS配置优化版) 1. 为什么选择Proxmox VE搭建家庭实验室? 对于个人开发者和技术爱好者来说,拥有一套完整的虚拟化环境是提升技术能力的绝佳途径。Proxmox VE作为…...
汽车线控转向系统动力学法Carsim和Simulink联合仿真
✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...
别再只调PID了!基于STM32C8T6的电磁循迹小车,从硬件滤波到软件算法的抗干扰全攻略
电磁循迹小车的抗干扰实战:从硬件滤波到软件优化的全链路解决方案 当你的电磁循迹小车在实验室里跑得风生水起,一到比赛现场却频频"抽风",这往往不是PID参数调得不够好,而是整个系统的抗干扰设计存在漏洞。本文将带你深…...
AI赋能Spring开发:借助快马平台快速集成Spring AI,打造智能应用
AI赋能Spring开发:借助快马平台快速集成Spring AI,打造智能应用 Spring生态庞大,新技术集成往往需要查阅大量文档。最近我在尝试将Spring AI集成到项目中,发现这个过程比想象中要复杂得多。好在发现了InsCode(快马)平台ÿ…...
FPGA Multiboot翻车实录:从XDC配置到ICAPE2,我的W25Q128分区血泪史与避坑指南
FPGA Multiboot实战:从配置陷阱到Flash分区优化的全流程解析 第一次在量产产品中实现FPGA远程更新功能时,我盯着实验室里突然变砖的开发板,后背渗出一层冷汗。原本以为按照官方文档配置就能万无一失,没想到Multiboot这个看似简单的…...
WavePWM库:嵌入式LED正弦调光算法与实现
1. WavePWM库概述:正弦波形LED调光的底层实现原理与工程应用 WavePWM是一个面向嵌入式LED驱动场景的轻量级波形PWM计算库,其核心价值不在于直接控制硬件引脚,而在于 以确定性数学模型生成高保真度的正弦(或类正弦/指数࿰…...
PCB设计新手必看:从零开始掌握PCB设计全流程
1. PCB设计入门:从零开始的完整指南 刚接触PCB设计时,我完全被各种专业术语和复杂流程搞懵了。直到自己动手做了几块板子,才发现其实只要掌握正确的方法,PCB设计并没有想象中那么难。这篇文章就是把我踩过的坑和积累的经验&#x…...
后端/全栈/架构师转战AI大模型开发:可落地规划(建议收藏)
如果你本身是后端、全栈或架构师出身,就意味着你已经手握一套扎实的“确定性系统”构建能力——分布式部署、高并发处理、数据库事务管控、系统稳定性保障,这些都是你转型AI大模型开发的核心底牌,也是纯算法出身从业者难以快速补齐的短板。 而…...
OpenClaw技能扩展指南:为百川2-13B添加公众号发布模块
OpenClaw技能扩展指南:为百川2-13B添加公众号发布模块 1. 为什么需要公众号发布技能 上周我正忙着准备一篇技术分享文章,突然意识到一个痛点:每次写完Markdown文档后,手动复制到公众号编辑器、调整格式、上传封面、设置摘要的过…...
Ryujinx:高性能Nintendo Switch模拟器技术指南
Ryujinx:高性能Nintendo Switch模拟器技术指南 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx Ryujinx是一款采用C#开发的开源Nintendo Switch模拟器,它通过精确…...
