ThreadLocal共享变量
一、ThreadLocal
我们知道多线程访问同一个共享变量时,会出现线程安全问题,为了保证线程安全开发者需要对共享变量的访问操作进行适当的同步操作,如加锁等同步操作。
除此之外,Java提供了ThreadLocal类,当一个共享变量使用ThreadLocal声明时,它表明,当每个线程访问共享变量时,会把共享变量复制一份到线程的工作内存,之后线程对此共享变量进行操作时操作的都是线程工作内存的变量而不是主内存中的共享变量,从而不需要加锁的同步操作实现避免出现线程安全问题。
二、Thread使用代码示例
public class ThreadLocalTest {private static ThreadLocal<String> variable = new ThreadLocal<>(); // (1) public static void main(String[] args) throws InterruptedException {variable.set(Thread.currentThread().getName()); // (2)// 创建线程一var thread1 = new Thread(() -> {System.err.println("Thread Name before set: " + Thread.currentThread().getName() + " " + variable.get()); // (3)variable.set(Thread.currentThread().getName()); // (4)System.err.println("Thread Name after set: " + Thread.currentThread().getName() + " " + variable.get()); // (5)});var thread2 = new Thread(() -> {System.err.println("Thread Name before set: " + Thread.currentThread().getName() + " " + variable.get()); // (6)variable.set(Thread.currentThread().getName()); // (7)System.err.println("Thread Name after set: " + Thread.currentThread().getName() + " " + variable.get()); // (8)});thread1.start(); // (9)thread2.start(); // (10)Thread.sleep(2000); // (11)System.err.println("main thread: " + variable.get()); // (12)}
}
输出:
Thread2 before set: Thread-1 null
Thread2 after set: Thread-1 Thread-1
Thread1 before set: Thread-0 null
Thread1 after set: Thread-0 Thread-0
main thread: main
示例中我们创建了两个线程,每个线程里都读取和设置全局的ThreadLcoal变量:
代码(1)创建了一个ThreadLocal共享变量variable,这里其实设置的是主线程工作内存里的共享变量副本
代码(2)主线程设置ThreadLocal变量variable
代码(3)线程一读取共享变量variable的值
代码(4)线程一设置共享变了variable的值,这里其实设置的是线程一工作内存里的共享变量副本
代码(5)线程一再次读取共享变量variable的值
代码(6)线程二读取共享变量variable的值
代码(7)线程二设置共享变了variable的值,这里其实设置的是线程二工作内存里的共享变量副本
代码(8)线程二再次读取共享变量variable的值
代码(9)启动线程一
代码(10)启动线程二
代码(11)主线程休眠2秒
代码(12)主线程读取共享变量variable的值
从输出我们可以看到,每个两个线程所操作的ThreadLocal变量互不影响,其实每个线程在设置和读取共享变量variable时操作的都是共享变量在线程自己工作内存里的副本,并不会影响到其他线程的值。
三、ThreadLocal原理
我们说线程操作ThreadLocal类型的变量时,会复制一个变量副本到线程工作空间,然后所有操作都是对副本变量进行的。那线程是怎么复制ThreadLocal变量到线程工作空间的,线程和ThreadLocal之前是怎么关联的。首先我们来看一看Thread的结构
可以看到Thread类有很多属性,我们现在只关心threadLocals
和inheritableThreadLocals
,这两个变量都是ThreadLocalMap类型的实例。TThreadLocalMap是一个ThreadLocal.ThreadLocalMap类型,这是一个特殊的Map。
首先看一下在前面的例子中我们是怎么在线程中使用ThreadLocal变量的,
variable.set(Thread.currentThread().getName()); // 设置ThreadLocal变量
variable.get(); // 读取ThreadLocal变量
接下来我们看看ThreadLocal变量的set和get方法。
ThreadLocal.get()
相关源码如下:
public T get() {return get(Thread.currentThread()); // (1)
}private T get(Thread t) {ThreadLocalMap map = getMap(t); // (2)if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this); // (3)if (e != null) {@SuppressWarnings("unchecked")T result = (T) e.value;return result;}}return setInitialValue(t); // (4)
}ThreadLocalMap getMap(Thread t) {return t.threadLocals; // (5)
}
从代码(1)可以看到,调用ThreadLocal的get()方法时,会将当前线程作为参数传递。代码(2)调用getMap方法获取ThreadLocalMap类型变量,如果map不为空则把ThreadLocal实例作为key获取值,这个值就是ThreadLocal变量的值(5)可以看到getMap方法返回的就是Thread类型的threadLocals变量。根据上述分析我们可以知道:
线程在读取ThreadLocal变量时,实际是获取当前线程的threadLocals变量,然后把ThreadLocal实例当做key从threadLocals查询对应的值。也就是说线程读取的ThreadLocal的实际值并不是存在ThreadLocal实例里的,而是存在线程的threadLocals里面,threadLocals是一个ThreadLocal.ThreadLocalMap,这是一个特殊的Map,key为ThreadLocal实例,值为ThreadLocal变量的实际值。ThreadLoca相当于一个转接口,连接Thread和ThreadLocal。
代码(4)可以看到如果当前线程的threadLocals变量为null,会调用ThreadLocal的setInitialValue方法初始化当前线程的threadLocals实例。
private T setInitialValue(Thread t) {T value = initialValue();ThreadLocalMap map = getMap(t);if (map != null) {map.set(this, value);} else {createMap(t, value);}if (this instanceof TerminatingThreadLocal<?> ttl) {TerminatingThreadLocal.register(ttl);}if (TRACE_VTHREAD_LOCALS) {dumpStackIfVirtualThread();}return value;
}void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue); // (1)
}
setInitialValue
方法会创建参数传递线程的threadLocals值,并且设置一个初始化值。从代码(1)可以看到threadLocals的key为ThreadLocal实例。
下面再看看ThreadLocal的set方法:
public void set(T value) {set(Thread.currentThread(), value); // (1)if (TRACE_VTHREAD_LOCALS) {dumpStackIfVirtualThread();}
}private void set(Thread t, T value) {ThreadLocalMap map = getMap(t);if (map != null) {map.set(this, value);} else {createMap(t, value);}
}
从代码(1)可以看到,调用ThreadLocald的set方法会向当前线程的threadLocals变量里设置传递的值value,key为ThreadLocal实例的引用,和get方法一样,如果当前线程的threadLocals变量为null,则会创建一个ThreadLocalMap变量并把value设置为初始值。
总结:在每个线程内部都有一个threadLocals变量,该变量类型为ThreadLocal.ThreadLocalMap,其中key为我们定义的ThreadLocal变量的this引用,value则为我们使用set方法设置的值。每个线程的本地变量存放在线程自己的内存变量threadLocals中。
如果线程不销毁,那么对应的本地变量就会一直存在,所以可能存在内存溢出,因此使用完毕之后要记得调用ThreadLocal的remove方法删除对应线程的threadLocals变量里的值。
注意:ThreadLocal不具备继承性,也就是说子线程并不能访问父线程的ThreadLocal变量。
相关文章:
ThreadLocal共享变量
一、ThreadLocal 我们知道多线程访问同一个共享变量时,会出现线程安全问题,为了保证线程安全开发者需要对共享变量的访问操作进行适当的同步操作,如加锁等同步操作。 除此之外,Java提供了ThreadLocal类,当一个共享变…...
前端crypto-js 库: MD5
文章目录 什么是crypto-js安装依赖MD5 什么是crypto-js github地址: https://github.com/brix/crypto-js cryptojs文档: https://cryptojs.gitbook.io/docs/#encoders CryptoJS (crypto.js) 为 JavaScript 提供了各种各样的加密算法。 CryptoJS是一个JavaScript加密算法库&a…...
2024新年快乐
2024-1-1 祝福大家和自己健康喜乐,升职加薪,新年快乐 页面加载事件load 我们页面加载事件的触发是等所有的资源加载完毕时触发该事件。和click一样是事件,但是触发时机是等资源加载(浏览器)完毕。这个事件我们可以将…...
OpenCV-Python(21):轮廓特征及周长、面积凸包检测和形状近似
2. 轮廓特征 轮廓特征是指由轮廓形状和结构衍生出来的一些特征参数。这些特征参数可以用于图像识别、目标检测和形状分析等应用中。常见的轮廓特征包括: 面积:轮廓所包围的区域的面积。周长:轮廓的周长,即轮廓线的长度。弧长&…...
连接progressql报错Cannot load JDBC driver class ‘org.postgresql.Driver‘,亲测有效!!!
Jmeter连接progressql报错Cannot load JDBC driver class ‘org.postgresql.Driver’ 1.到官方下载驱动注意:根据项目的JDK版本来下载对应的驱动Download | pgJDBC 2.将postgresql-42.2.27.jar复制到lib目录下面, 然后重新启动 连接driver信息如下&#…...
SQLAlchemy快速入门
安装依赖 pip install sqlalchemy pip install pymysql创建数据库和表 # 创建数据库 drop database if exists sqlalchemy_demo; create database sqlalchemy_demo character set utf8mb4; use sqlalchemy_demo;# 创建表 drop table if exists user; create table user (id …...
java 纯代码导出pdf合并单元格
java 纯代码导出pdf合并单元格 接上篇博客 java导出pdf(纯代码实现) 后有一部分猿友叫我提供一下源码,实际上我的源码已经贴在帖子上了,都是同样的步骤,只是加多一点设置就可以了。今天我再次上传一下相对情况比较完整…...
Linux自己的应用商店yum
💫Linux系统如何安装软件 在Linux系统中我们可以通过多种方式安装软件,常见方式有以下三种: 1.源代码安装 2.rpm包安装 3.使用yum软件包管理器安装 早期人们通过下载软件源代码,然后再经过交叉编译等一系列工作下…...
集成电路模拟设计——【基于Serdes 应用的 串化/解串器 时钟与数据恢复电路CDR】
串化/解串器 & 时钟与数据恢复电路CDR(可提供实现过程、仿真波形与具体参数细节 本文内容摘要背景串化/解串器全速树形串化器半速树形串化器全速移位寄存器串化器多级树形解串器 PLL型CDR整体架构实现结果 Bang-Bang型CDR整体架构 PS/PI型CDR电路PS电路设计PI电…...
OpenWrt 编译入门(小白版)
编译环境 示例编译所用系统为 Ubuntu 22.04,信息如下 编译时由于网络问题,部分软件包可能出现下载问题,还请自备网络工具或尝试重新运行命令 编译步骤 下图为官网指示 编译环境设置(Build system setup) 这里根据我…...
嵌入式视频播放器(mplayer)
1.文件准备: MPlayer-1.0rc2.tar.bz2 libmad-0.15.1b.tar.gz 直接Git到本地 git clone https://gitee.com/zxz_FINE/mplayer_tarball.git 2.文件夹准备: src存放解压后的源码文件,target_Mplayer存放编译安装的目标文件 mkdir src targe…...
对房价数据集进行处理和数据分析
大家好,我是带我去滑雪,每天教你一个小技巧! 房价数据集通常包含各种各样的特征,如房屋面积、地理位置、建造年份等。通过对数据进行处理和分析,可以更好地理解这些特征之间的关系,以及它们对房价的影响程度…...
BERT的学习
BERT 1.前言 self-supervised learning是一种无监督学习的特殊形式,算法从数据本身生成标签或者目标,然后利用这些生成的目标来进行学习。(也就是说数据集的标签是模型自动生成的,不是由人为提供的。)例如࿰…...
数据结构OJ实验9-图存储结构和遍历
A. 图综合练习--构建邻接表 题目描述 已知一有向图,构建该图对应的邻接表。 邻接表包含数组和单链表两种数据结构,其中每个数组元素也是单链表的头结点,数组元素包含两个属性,属性一是顶点编号info,属性二是指针域n…...
20231226在Firefly的AIO-3399J开发板上在Android11下调通后摄像头ov13850
20231226在Firefly的AIO-3399J开发板上在Android11下调通后摄像头ov13850 2023/12/26 8:22 开发板:Firefly的AIO-3399J【RK3399】 SDK:rk3399-android-11-r20211216.tar.xz【Android11】 Android11.0.tar.bz2.aa【ToyBrick】 Android11.0.tar.bz2.ab And…...
0101包冲突导致安装docker失败-docker-云原生
文章目录 1 前言2 报错3 解决结语 1 前言 最近在学习k8s,前置条件就是要安装指定版本的docker,命令如下 yum install -y docker-ce-20.10.7 docker-ce-cli-20.10.7 containerd.io-1.4.62 报错 file /usr/libexec/docker/cli-plugins/docker-buildx fr…...
【力扣100】17.电话号码的字母组合
添加链接描述 class Solution:def letterCombinations(self, digits: str) -> List[str]:# 思路是使用回溯算法if not digits:return []phone {2:[a,b,c],3:[d,e,f],4:[g,h,i],5:[j,k,l],6:[m,n,o],7:[p,q,r,s],8:[t,u,v],9:[w,x,y,z]}def backtrack(con,dig):# 收获if le…...
2023。
一月 从头开始 二月 准备复试&初试成绩 三月 最开心 过了两个生日(这机率,幸运儿) 考研也成功上岸!nnuGISer! 四月 和室友去了趟武汉 五月 拍毕业照 六月 人生高光时刻 省创!上台领奖!考研…...
出现 Cause: java.sql.SQLException: Field ‘id‘ doesn‘t have a default value解决方法
目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 在驱动Springboot项目的时候,出现如下问题: org.springframework.dao.DataIntegrityViolationException: ### Error updating database. Cause: java.sql...
Linux--批量自动装机
实验环境 随着某公司业务不断发展,服务器主机的数量也迅速增长,对于功能变更或新采购的服务器, 需要重新安装CentOS7操作系统,为了提高服务器装机效率,要求基于PXE网络实现全自动无人值 守批量安装。 需求描述 > 服…...
病理HE学习贴(自备)
目录 正常结构 癌症HE 在线学习 以胃癌的学习为例 正常结构 1:胃粘膜正常结构和细胞分化 ●表面覆盖小凹上皮细胞(主要标志物:MUC5AC)以保护黏膜。 ●胃底腺固有腺体由黏液颈细胞(MUC6)、主细胞(Pepsinogen l)和壁细胞(Proton pump α-subunit)组…...
关于协同过滤算法在物联网的应用-基于用户行为数据和物联网设备数据,以此提供个性化的智能家居控制推荐服务
关于协同过滤算法在物联网领域的应用的一个案例是基于用户行为数据和物联网设备数据,为用户提供个性化的智能家居控制推荐服务。 具体实现如下: 数据收集:收集用户对智能家居设备的使用行为数据,包括设备的打开、关闭、调节等操…...
计算机网络(6):应用层
每个应用层协议都是为了解决某一类应用问题,而问题的解决又往往是通过位于不同主机中的多个应用进程之间的通信和协同工作来完成的。 应用层的具体内容就是规定应用进程在通信时所遵循的协议。 应用层的许多协议都是基于客户服务器方式。即使是对等通信方式&#x…...
ESP32:整合存储配网信息和MQTT笔记
文章目录 1.给LED和KEY的所用IO增加配置项1.1 增加配置文件1.2 修改相应的c源码 2. 把mqtt\tcp的工程整合到一起2.1 在何处调用 mqtt_app_start() 3. 测试MQTT4. 完整的工程源码 有一段时间没有玩ESP32,很多知识点都忘记了。今天测试一下MQTT,做个笔记。…...
nginx源码分析-4
这一章内容讲述nginx的模块化。 ngx_module_t:一个结构体,用于描述nginx中的各个模块,其中包括核心模块、HTTP模块、事件模块等。这个结构体包含了一些模块的关键信息和回调函数,以便nginx在运行时能够正确地加载和管理这些模块。…...
【Unity美术】Unity工程师对3D模型需要达到的了解【二】
👨💻个人主页:元宇宙-秩沅 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 秩沅 原创 👨💻 收录于专栏:Uni…...
《微信小程序开发从入门到实战》学习六十九
6.6 网络API 6.6.3 下载文件API 使用 wx.downloadFile 接口是可使小程序发起HTTPS GET请求,下载文件到手机端。 单次下载的最大文件为50MB。接受Obkect参,参支持属性如下: url(必填):下载文件的URL he…...
2022年全球软件质量效能大会(QECon北京站2022)-核心PPT资料下载
一、峰会简介 当前,新一轮科技革命和产业变革正在重塑全球经济格局,以云计算为代表的新一代信息技术创新活跃,与实体经济深度融合,推动泛在连接、数据驱动、智能引领的数字经济新形式孕育而生。 新兴技术的出现给测试乃至整个软…...
ILI9481 TFT3.5寸屏STM32F446ZEXX FMC驱动方式详解
图片来源于网络,如若侵权请联系博主删除 文章目录 1. 背景2. 基础知识2.1 TFT-LCD2.2 硬件接线2.3 FMC2.4 ILI9481 3. 软件抽象 1. 背景 最近做项目需要,博主在某宝上买了一块3.5寸的TFT屏,店家虽然发了资料,但是往产品上移植驱动…...
010、切片
除了引用,Rust还有另外一种不持有所有权的数据类型:切片(slice)。切片允许我们引用集合中某一段连续的元素序列,而不是整个集合。 考虑这样一个小问题:编写一个搜索函数,它接收字符串作为参数&a…...
【华为数据之道学习笔记】8-6 质量改进
数据质量改进致力于增强满足数据质量要求的能力。数据质量改进消除系统性的问题,对现有的质量水平在控制的基础上加以提高,使质量达到一个新水平、新高度。 质量改进的步骤本身就是一个PDCA循环。质量改进包括涉及企业跨组织的变革性改进(BTM…...
python多环境管理工具——pyenv-win安装与使用教程
目录 pyenv-win简介 pyenv-win安装 配置环境变量 pyenv的基本命令 pyenv安装py环境 pyenv安装遇到问题 pycharm测试 pyenv-win简介 什么是pyenv-win: 是一个在windows系统上管理python版本的工具。它是pyenv的windows版本,旨在提供类似于unix/li…...
Excel报表框架(ExcelReport)极简化解决复杂报表导出问题
Excel Report 耗费了半个月的时间,终于在元旦这三天把报表框架开发完成了,使用该框架你可以非常方便的导出复杂的Excel报表。 项目开源地址: GiteeGithub 前言 不知道各位在使用POI开发报表导出过程中遇到过以下的情况: 频繁…...
常用设计模式全面总结版(JavaKotlin)
这篇文章主要是针对之前博客的下列文章的总结版本: 《设计模式系列学习笔记》《Kotlin核心编程》笔记:设计模式【Android知识笔记】FrameWork中的设计模式主要为了在学习了 Kotlin 之后,将 Java 的设计模式实现与 Kotin 的实现放在一起做一个对比。 一、创建型模式 单例模…...
Docker自建私人云盘系统
Docker自建私人云盘系统。 有个人云盘需求的人,主要需求有这几类: 文件同步、分享需要。 照片、视频同步需要,尤其是全家人都是用的同步。 影视观看需要(分为家庭内部、家庭外部) 搭建个人网站/博客 云端OFFICE需…...
python replace()方法 指定替换指定字段
replace()方法 使用方法 str.replace(old, new[, max]) Python replace() 方法把字符串中的 old(旧字符串) 替换成 new(新字符串),如果指定第三个参数max,则替换不超过 max 次。 示例 #!/usr/bin/pythonstr "this is s…...
【仅供测试】
https://microsoftedge.microsoft.com/addons/detail/%E7%AF%A1%E6%94%B9%E7%8C%B4/iikmkjmpaadaobahmlepeloendndfphd 测试网站: https://www.alipan.com/s/tJ5uzFvp2aF // UserScript // name 阿里云盘助手 // namespace http://tampermonkey.net/ // …...
C#/WPF JSON序列化和反序列化
什么是json json是存储和交换文本信息的方法,类似xml。但是json比xml更小,更快,更易于解析。并且json采用完全独立于语言的文本格式(即不依赖于各种编程语言),这些特性使json成为理想的数据交换语言。json序列化是指将对象转换成j…...
Java——ArraryList线程不安全
目录 前言一、为什么ArraryList线程不安全?二、具体可以看debug源码后续敬请期待 前言 Java——ArraryList线程不安全 一、为什么ArraryList线程不安全? 因为没有synchronized,这个关键字做线程互斥,没有这个关键字,…...
基于Java SSM框架实现健康管理系统项目【项目源码】
基于java的SSM框架实现健康管理系统演示 JSP技术 JSP是一种跨平台的网页技术,最终实现网页的动态效果,与ASP技术类似,都是在HTML中混合一些程序的相关代码,运用语言引擎来执行代码,JSP能够实现与管理员的交互…...
PostgreSQL16.1(Windows版本)
1、卸载原有的PostgreSQL   点击Next即可。  点击OK即可。 卸载完成。 2、安装 (1) 前两部直接Next,第二部可以换成自己想要安装的路径。 (2) 直接点击Next。…...
使用nodejs对接arXiv文献API
GPT4.0国内站点: 海鲸AI-支持GPT(3.5/4.0),文件分析,AI绘图 要使用 Node.js 对接 arXiv 的 API,你可以使用 axios 库或者 Node.js 的内置 http 模块来发送 HTTP 请求。以下是一个简单的例子,展示了如何使用 axios 来获取 arXiv 上…...
mac 安装pyaudio
直接安装pyaudio时报错 ERROR: Could not build wheels for PyAudio, which is required to install pyproject.toml-based projects需要先安装portaudio,打开终端执行: brew install portaudio再安装pyaudio成功 pip3 install pyaudioportaudio是一个…...
k8s学习 — 各章节重要知识点
k8s学习 — 各章节重要知识点 学习资料k8s版本0 相关命令0.1 yaml配置文件中粘贴内容格式混乱的解决办法0.2 通用命令0.3 Node 相关命令0.4 Pod 相关命令0.5 Deployment 相关命令0.6 Service 相关命令0.7 Namespace 相关命令 1 k8s学习 — 第一章 核心概念1.1 Pod、Node、Servi…...
go slice源码探索(切片、copy、扩容)和go编译源码分析
文章目录 概要一、数据结构二、初始化2.1、字面量2.2、下标截取2.2.1、截取原理 2.3、make关键字2.3.1、编译时 三、复制3.1、copy源码 四、扩容4.1、append源码 五:切片的GC六:切片使用注意事项七:参考 概要 Go语言的切片(slice…...
电影“AI化”已成定局,华为、小米转战入局又将带来什么?
从华为、Pika、小米等联合打造电影工业化实验室、到Pika爆火,再到国内首部AI全流程制作《愚公移山》开机……业内频繁的新动态似乎都在预示着2023年国内电影开始加速进入新的制片阶段,国内AI电影热潮即将来袭。 此时以华为为首的底层技术科技企业加入赛…...
小程序for循环中key值的作用?
在小程序的 for 循环中,key 值有两个主要作用: 识别列表项的唯一性:当在列表渲染时使用 for 循环,每个列表项都应该具有一个唯一的 key 值。这个 key 值用于帮助小程序识别每个列表项的唯一性,以便在列表发生变化时进行…...
深入理解Dockerfile —— 筑梦之路
FROM 基础镜像 可以选择现有的镜像,比如centos、debian、apline等,特殊镜像scratch,它是一个空镜像。 如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。 不…...
Vue3 魔法:轻松删除响应式对象的属性
🧙♂️ 诸位好,吾乃诸葛妙计,编程界之翘楚,代码之大师。算法如流水,逻辑如棋局。 📜 吾之笔记,内含诸般技术之秘诀。吾欲以此笔记,传授编程之道,助汝解技术难题。 &…...
python命令大全及说明,python命令大全下载
大家好,本文将围绕python命令大全及说明展开说明,python命令大全下载是一个很多人都想弄明白的事情,想搞清楚python简单命令语句需要先了解以下几个事情。 Python有哪些常用但容易忘记的命令? 1 如何忽略报错信息2 Python常见绘图…...