ThreadLocal解析
ThreadLocal是一个存储线程本地变量的对象,在ThreadLocal中存储的对象在其他线程中是不可见的,本文介绍ThreadLocal的原理。
1、threadLocal使用
有如下代码:
@Slf4j
public class TestThreadLocal {public static void main(String[] args) {ThreadLocal<Integer> threadLocal = new ThreadLocal<>();threadLocal.set(999);log.info(threadLocal.get().toString());//使用线程池创建一个线程ExecutorService service = Executors.newSingleThreadExecutor();service.execute(()->{log.info(threadLocal.get().toString());//threadLocal.get()将为nullthreadLocal.set(888);log.info(threadLocal.get().toString());});log.info(threadLocal.get().toString());}
}
输出:
2023-03-09 09:03:40.572 [main] INFO -- 999
2023-03-09 09:03:40.598 [main] INFO -- 999
Exception in thread "pool-1-thread-1" java.lang.NullPointerExceptionat com.iwat.arithmetic.thread.TestThreadLocal.lambda$main$0(TestThreadLocal.java:24)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
从结果中可以看到,在新线程中无法获取到999,祝线程中set的数,只有祝线程能get到,这就保证了变量的线程唯一。
2、原理
原理就要看源码
首先看threadLocal.set(999);的源码
//ThreadLocal类中public void set(T value) {//1.获取当前线程Thread t = Thread.currentThread();//2. 获取线程中的ThreadLocalMap对象ThreadLocalMap map = getMap(t);if (map != null)//线程中的ThreadLocalMap对象不为空,直接set值,this就是当前ThreadLocal对象没,值就是值map.set(this, value);else//线程中的ThreadLocalMap对象为空,创建并set值createMap(t, value);}
很简单,获取当前线程,然后获取当前线程的ThreadLocalMap对象,这里的ThreadLocalMap可以就当做一个Map处理,但是这个Map不一样的地方在于key只能是ThreadLocal对象。现在我们就可以分析一下了。

每一线程都有一个ThreadLocalMap对象,对于每一个ThreadLocal对象来说它可以在每一个线程中ThreadLocalMap中存一个以它为key的值。例如:
- 在线程1中,ThreadLocal对象1执行set方法,实际上就是在线程1中的ThreadLocalMap中添加一个k-v(1号红色箭头),k就是ThreadLocal对象1。
- 在线程1中,ThreadLocal对象2执行get方法,就是在线程1的ThreadLocalMap中获取以ThreadLocal对象2为key的值(2号红色箭头)
每个ThreadLocal在某个线程中只能有一个对应value,因为Map中key不能重复,这就实现了线程唯一变量的功能。
下面看一下ThreadLocal中的get方法验证一下分析:
//ThreadLocal类中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();}
同时这也解释了,为什么上面代码中出现Exception in thread "pool-1-thread-1" java.lang.NullPointerException,原因就是在新创建的线程中的ThreadLocalMap中没有以当前ThreadLocal对象为key的值。
3、java引用类型
3.1 GC回收对象
java垃圾回收器多采用可达性分析算法来确定一个java对象需不需要回收,过程是这样的:
- 首先确定一些一定不能回收的对象,叫做GCRoot对象
- 查找GCRoot对象引用的对象
- 然后沿着引用链一直找(注意:引用有多种类型)
最终根据对象被引用的类型、有没有被引用,来决定是不是回收这个对象。
3.2 引用类型
那么引用类型有哪些呢?总体而言分为四种:
- 强引用
沿着GC Root引用链可以找到的对象就是强引用对象 - 软引用 (SoftReference)
垃圾回收后仍内存不足,就会回收掉 - 弱号1用 (WeakReference)
垃圾回收就将其回收掉 - 虚引用 (PhantomReference)
必须配合引用队列使用,主要配合 ByteButfer 使用,被引用对象回收时,会将虛引用入队,由
Reference Handler 线程调用虚引用相关方法释放直接内存

4、内存泄漏问题
在看了java中几种引用类型之后在看内存泄漏问题,什么是内存泄漏?就是指一部分对象一直占用内存,也清不掉,就好像这块内存空间没了,漏掉了。
其实在ThreadLocalMap的内部使用的是Entry类存储k-v
static class ThreadLocalMap {static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}/*** The initial capacity -- MUST be a power of two.*/private static final int INITIAL_CAPACITY = 16;//省略若干代码
}
可以看到Entry在实现时继承了弱引用,为什么这样呢?看注释是这样说的
The entries in this hash map extend WeakReference, using its main ref field as the key (which is always a ThreadLocal object). Note that null keys (i.e. entry.get() == null) mean that the key is no longer referenced, so the entry can be expunged from table. Such entries are referred to as "stale entries" in the code that follows.Note that null keys (i.e. entry.get()* == null)
如果 key threadlocal 为 null 了,这个 entry 就可以清除了。
ThreadLocal是一个弱引用,当为null时,会被当成垃圾回收 。
在ThreadLocal的使用时,线程的ThreadLocalMap中都存储了以ThreadLocal为key的值,如果ThreadLocal被清理了,那么
ThreadLocalMap中对应的数据会被清理吗?
并不会,原因是ThreadLocal被清理变成null之后,ThreadLocalMap被Thread所引用(强引用)并不会回收,只是key变成了null。
如何解决呢内存泄漏呢?最简单的办法就是用完之后remove,ThreadLocal不用了,就去ThreadLocalMap中清理到对用的k-v。
相关文章:
ThreadLocal解析
ThreadLocal是一个存储线程本地变量的对象,在ThreadLocal中存储的对象在其他线程中是不可见的,本文介绍ThreadLocal的原理。 1、threadLocal使用 有如下代码: Slf4j public class TestThreadLocal {public static void main(String[] args…...
时间格式表
时间格式化对照表 仅供参考标识符含义aAM/PM(上午/下午)A0~86399999 (一天的第A微秒)c/cc1~7 (一周的第一天, 周天为1)cccSun/Mon/Tue/Wed/Thu/Fri/Sat (星期几简写)ccccSunday/Monday/Tuesday/Wednesday/Thursday/Friday/Saturday (星期几全拼)d1~31 (月份的第几天, 带0)D1~36…...
enscape和twinmotion哪个好用?
Twinmotion 和 Enscape这2款渲染软件最近受到了一些初学者的关注。这 2 个软件适用于那些需要 3D 渲染但质量不是他们项目的首要任务的人。在本文中,我们将对Twinmotion 和 Enscape 进行面对面的比较,并帮助您确定哪一个更适合您。什么是 Twinmotion&…...
Canvas
canvas介绍 什么是 Canvas?Canvas 是为了解决 Web 页面中只能显示静态图片这个问题而提出的,一个可以使用 JavaScript 等脚本语言向其中绘制图像的 HTML 标签。 Canvas 解决了什么问题 我在 MSDN(《Microsoft Developer Network》是微软一…...
旅游预约APP开发具有什么优势和功能
旅游活动目前正在作为广大用户休闲娱乐的一个首选内容,不仅是公司团建活动可以选择旅游,而且一些节假日也可以集结自己的亲朋好友来一次快乐有趣的旅游活动,随着当代人对于旅游的需求呈现上升的趋势,也让旅游预约APP开发开始流行并…...
Python之函数参数细讲
文章目录前言一、了解形式参数和实际参数1. 通过作用理解2. 通过一个比喻来理解形式参数和实际参数二、位置参数1. 数量必须与定义时一致2. 位置必须与定义时一致三、关键字参数四、为参数设置默认值五、可变参数1. *parameter2. **parameter总结前言 在调用函数时,…...
跑步耳机入耳好还是不入耳好、十大跑步运动耳机品牌排行榜推荐
健身房经常会播放一些节奏较快的歌曲,这样能够激发大家在运动过程中的动力,所以运动时聆听音乐确实比较有效果,居家运动、室外跑步时选择运动耳机就变成了刚需,首先不能影响其他人、佩戴时要稳定,音质和续航要有保证&a…...
Go语言容器之数组和切片
Go语言的容器分为值类型和引用数据类型 一、数组 1.数组的声明和初始化 (1) 数组声明的语法 var 数组变量名 [数组大小]数组类型 举例: package main import "fmt"func main(){//数组的声明var arr[10]int//打印数组长度fmt.Println("arr的长度为…...
【ROS2知识】humble下使用插件编程
Creating and using plugins (C++) — ROS 2 Documentation: Humble documentation 一、说明 接口编程的好处不言自明,有兴趣的朋友可以看看相关文章。此处在ROS2上进行接口编程,这是个技术难点,如果不能突破,那么许多方面将不能进行,比如:navigation中的costmap_2d包中…...
MySQL 主备一致
MySQL 主备一致主备切换binlog 格式statementrowmixed生产格式循环复制问题主备切换 MySQL 主备切换流程 : 状态 1 : 客户端的读写都直接访问节点 A,而节点 B 是 A 的备库,只将 A 的更新都同步过来 , 并本地执行。来保持节点 B 和 A 的数据是相同当切换…...
玩转CodeQLpy之用友GRP-U8漏洞挖掘
0x01 前言CodeQLpy是作者使用python3实现的基于CodeQL的java代码审计工具,github地址https://github.com/webraybtl/CodeQLpy。通过CodeQLpy可以辅助代码审计人员快速定位代码中的问题,目前支持对SprintBoot的jar包,SpringMVC的war包…...
GMP调度模型总结
优秀文章 什么是GMP调度模型 Golang的一大特色就是Goroutine。Goroutine是Golang支持高并发的重要保障。Golang可以创建成千上万个Goroutine来处理任务,将这些Goroutine分配、负载、调度到处理器上采用的是G-M-P模型。 什么是Goroutine Goroutine Golang Coro…...
蓝桥回文日期题
题目 题目描述 2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。 有人表示 20200202 是 “千年…...
【2023】某python语言程序设计跟学第三周内容
目录1.数字类型与操作:整数:浮点数:复数数值运算操作符数字之间关系数值运算函数2.案例:天天向上的力量第一问:1‰的力量第二问:5‰和1%的力量第三问:工作日的力量第四问:工作日的努…...
c++11右值引发的概念
右值引用右值&&左值c11增加了一个新的类型,右值引用,记作:&&左值是指在内存中有明确的地址,我们可以找到这块地址的数据(可取地址)右值是只提供数据,无法找到地址(不…...
MySQL 02 :三层结构、备份删除数据库
MySQL 02 :数据库三层结构-破除MySQL神秘 请添加图片描述 通过golang操作MySQL 创建删除数据库 备份恢复数据库 第一次需要配置环境,否则会报错 报错:mysqldump: Got error: 1045: Access denied for user ‘root’‘localhost’ (using …...
质量员错题合集
项目部质量员根据规范要求认为,接地用的绝缘铜电线规定最小截面为( )mm。4 项目部质量员根据规范要求认为,接地用的绝缘铜电线规定最小截面为4mm,是从( )性能考虑的。机械、 案例中所使用的ZST型闭式喷头的工作压力是( )MPa。1.2 案例中所…...
请教大神们,pmp考试和复习有什么攻略诀窍吗?
PMP考试通过率挺高的,很多考生也是朝九晚五甚至天天加班的打工人,还是有很多人通过了的,我也是下班后和周末才有时间学习的,3A通过,但不是什么考试大神,每天抽出3-4个小时跟着培训机构制定的学习计划学习&a…...
Go语言基础之接口
Go语言基础之接口1.Go语言接口类型2.类型与接口的关系一个类型实现多个接口多种类型实现同一接口3.空接口4.类型断言1.Go语言接口类型 每个接口类型由任意个方法签名组成,接口的定义格式如下: type 接口类型名 interface{方法名1( 参数列表1 ) 返回值列…...
【Go自学第一节】GoLang 数据类型
和Java类型,go拥有多种数据类型,可以把它分为四个大类基础类型、聚合类型、引用类型和接口类型 一、基本数据类型 基本数据类型又可以细分为:数字类型(整型、浮点型)、布尔类型、字符串类型 整型 Go 的整型分为有符号…...
5分钟掌握:billd-desk跨平台远程控制高效解决方案
5分钟掌握:billd-desk跨平台远程控制高效解决方案 【免费下载链接】billd-desk 基于Vue3 WebRTC Nodejs Flutter搭建的远程桌面控制 项目地址: https://gitcode.com/gh_mirrors/bi/billd-desk 还在为远程办公的卡顿和限制而烦恼吗?当你急需远程…...
FPGA密码锁设计避坑指南:状态机划分、时序约束与安全逻辑的那些事儿
FPGA密码锁设计避坑指南:状态机划分、时序约束与安全逻辑的那些事儿 在FPGA开发领域,密码锁设计看似简单,实则暗藏玄机。许多工程师在完成基础功能后,往往会在状态机划分、时序约束和安全逻辑等环节踩坑。本文将结合实战经验&…...
3分钟掌握的网盘密码解析黑科技:让提取码自动获取效率提升10倍
3分钟掌握的网盘密码解析黑科技:让提取码自动获取效率提升10倍 【免费下载链接】baidupankey 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经因为寻找百度网盘分享链接的提取码而浪费大量时间?传统方式下,用户…...
Qwen3-TTS快速部署教程:一键启动Web服务,3分钟开始声音克隆
Qwen3-TTS快速部署教程:一键启动Web服务,3分钟开始声音克隆 1. 为什么选择Qwen3-TTS进行语音克隆 想象一下这样的场景:你需要为海外客户录制多语言产品介绍,但雇佣专业配音演员成本高昂;或者想为自己的视频内容添加个…...
AI读脸术备份恢复指南:手把手教你搭建高可用人脸识别服务
AI读脸术备份恢复指南:手把手教你搭建高可用人脸识别服务 1. 项目背景与需求分析 人脸识别技术已经成为现代数字服务的重要组成部分,从电商个性化推荐到智能安防系统,都依赖这项技术的稳定运行。AI读脸术镜像基于OpenCV DNN深度神经网络构建…...
内容营销对 SEO 有什么影响
<h3 id"seo">内容营销对 SEO 有什么影响</h3> <h4 id"">引言</h4> <p>在当今数字化时代,搜索引擎优化(SEO)和内容营销被广泛认为是网站流量和业务增长的关键驱动因素。许多企业在网站建设…...
7天掌握Driver Store Explorer:Windows驱动管理的完整指南
7天掌握Driver Store Explorer:Windows驱动管理的完整指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer [RAPR] 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer Driver Store Explorer(简称RAPR)是…...
SeqGPT-560M智能邮件分类系统实战
SeqGPT-560M智能邮件分类系统实战 1. 引言:邮件管理的痛点与解决方案 每天打开邮箱,看到堆积如山的未读邮件,是不是感觉头大?工作邮件、会议通知、促销信息、垃圾邮件全都混在一起,找重要邮件就像大海捞针。手动分类…...
XPath与lxml解析库
test.xml<?xml version"1.0" encoding"utf-8"?><bookstore><book name"halibote"><title lang"en">Harry Potter</title><author>J K. Rowling</author><year>2005</year>&l…...
忍者像素绘卷镜像免配置:一键切换‘天界画坊’/‘木叶村’双主题UI
忍者像素绘卷镜像免配置:一键切换天界画坊/木叶村双主题UI 1. 产品概述 忍者像素绘卷是一款专为像素艺术创作者设计的图像生成工作站,基于Z-Image-Turbo深度优化引擎开发。这款工具将传统忍者文化与现代AI技术完美结合,创造出独特的16-Bit复…...
