【SpringBoot】ThreadLocal 的详解

一、ThreadLocal 简介

ThreadLocal 叫做线程变量,意思是 ThreadLocal 中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal 为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

ThreadLocal 变量,线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本。这里有几点需要注意:

  • 因为每个 Thread 内有自己的实例副本,且该副本只能由当前 Thread 使用。这也是 ThreadLocal 命名的由来。
  • 既然每个 Thread 有自己的实例副本,且其它 Thread 不可访问,那就不存在多线程间共享的问题。

ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。

ThreadLocal 变量通常被 private static 修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。

下图可以增强理解:

 二、ThreadLocal 与 Synchronized 的区别

ThreadLocal<T> 其实是与线程绑定的一个变量。ThreadLocal 和 Synchorized 都用于解决多线程并发访问。

但是 ThreadLocal 和 Synchorized 有本质的区别:

  1. Synchorized 用于线程间的数据共享,而 ThreadLocal 则用于线程间的数据隔离。
  2. Synchorized 是利用锁的机制,使变量或代码块在某一时刻只能被一个线程访问。而 ThreadLocal 为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。

而 Synchorized 却正好相反,它用于在多个线程间通信时能够获得数据共享。

总结:

一句话理解 ThreadLocal ,threadLocal 是作为当前线程中属性 ThreadLocalMap 集合中的某一个 Entry 的 key 值,Entry(threadlocal,value),虽然不同的线程之间 threadLocal 这个 key 值是一样,但是不同的线程所拥有的 ThreadLocalMap 是独一无二的,也就是不同的线程间同一个 ThreadLocal(key)对应存储的值(value)不一样,从而到达了线程间变量隔离的目的,但是在同一个线程中这个 value 变量地址是一样的。

三、ThreadLocal 的简单使用

public class ThreadLocalTest {private static ThreadLocal<String> localVar = new ThreadLocal<String>();static void print(String str) {// 打印当前线程中本地内存中变量的值System.out.println(str + ":" + localVar.get());// 清除内存中的本地变量localVar.remove();}public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {@Overridepublic void run() {ThreadLocalTest.localVar.set("xdclass_A");print("A");// 打印本地变量System.out.println("清楚后:" + localVar.get());}}, "A").start();Thread.sleep(1000);new Thread(new Runnable() {@Overridepublic void run() {ThreadLocalTest.localVar.set("xdclass_B");print("B");// 打印本地变量System.out.println("清楚后:" + localVar.get());}}, "B").start();}
}A:xdclass_A
清楚后:null
B:xdclass_B
清楚后:null

从这个示例中我们可以看到,两个线程分别获取了自己线程存放的变量,他们之间变量的获取并不会错乱。这个的理解也可以结合图,相信会有一个更深刻地理解。

四、ThreadLocal 常见使用场景

ThreadLocal 适用于如下两种场景

  1. 每个线程需要有自己单独的实例
  2. 实例需要在多个方法中共享,但不希望被多线程共享

对于第一点,每个线程拥有自己实例,实现它的方式很多。例如可以在线程内部构建一个单独的实例。ThreadLoca 可以以非常方便的形式满足该需求。

对于第二点,可以在满足第一点(每个线程有自己的实例)的条件下,通过方法间引用传递的形式实现。ThreadLocal 使得代码耦合度更低,且实现更优雅。

存储用户 userInfo 场景:
@Slf4j
public class OnlineUserUtil {private final static ThreadLocal<UserInfo> threadLocal = new ThreadLocal<>();public static void set(UserInfo userInfo) {threadLocal.set(userInfo);}public static UserInfo get() {return threadLocal.get();}public static void remove() {threadLocal.remove();}}
@Slf4j
@Aspect
@Component
@Order(2)
public class TokenAuthenticationAspect {@Before(value = "@annotation(tokenAuthentication)")public void doBefore(JoinPoint pjp, TokenAuthentication tokenAuthentication) {// 校验代码log.info("验证成功,保存到threadLocal userInfo={}", userInfo);OnlineUserUtil.set(userInfo);}@AfterReturning(value = "@annotation(tokenAuthentication)")public void doAfter(TokenAuthentication tokenAuthentication) {OnlineUserUtil.remove();}}

这样在方法中,都能用到 userInfo 这个对象。

五、如何正确的使用 ThreadLocal

  1. 将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,由于一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,然后remove它,防止内存泄露。
  2. 每次使用完ThreadLocal,都调用它的remove()方法,清除数据。

六、参考文档

  • 史上最全ThreadLocal 详解(一)

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

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

相关文章

企业如何选择一款高效的ETL工具

企业如何选择一款高效的ETL工具? 在企业发展至一定规模后&#xff0c;构建数据仓库&#xff08;Data Warehouse&#xff09;和商业智能&#xff08;BI&#xff09;系统成为重要举措。在这个过程中&#xff0c;选择一款易于使用且功能强大的ETL平台至关重要&#xff0c;因为数…

Android:Google三方库之Firebase集成详细步骤(一)

前提条件 安装最新版本的 Android Studio&#xff0c;或更新为最新版本。使用您的 Google 账号登录 Firebase请注意&#xff0c;依赖于 Google Play 服务的 Firebase SDK 要求设备或模拟器上必须安装 Google Play 服务 将Firebase添加到应用&#xff1a; 方式&#xff1a;使用…

智慧工地综合管理平台-环境监测子系统概要设计说明书

需求说明 原始背景 由于城市建设和工业化进程的加速,工地施工过程中的部分环节由于监管不到位,导致工地扬尘污染问题日益严重,对人类健康和环境质量造成了不可忽视的影响。为了解决这一问题,政府部门和相关企业逐渐意识到了建立工地扬尘监测系统的必要性和紧迫性,因此,环…

运行代码时不同软件的参数写法

目录 pycharm终端 pycharm 如下图所示&#xff0c;不同参数间不需要什么间隔什么东西 终端 如下图所示&#xff0c;不同参数间需要用一个符号来间隔

npm ERR!问题解决

问题一 解决办法 两个文件夹【node_global】和【node_cache】 修改文件属性 问题二 解决办法 安装淘宝镜像 npm config set registry https://registry.npm.taobao.org 查看是否成功&#xff1a; npm config get registry 是淘宝的就ok

腾讯三季度财报解读:AI大模型成下个十年的新支点?

2023年&#xff0c;腾讯重回高增长轨道。 近日&#xff0c;腾讯披露了2023年第三季度财报&#xff0c;营收1546.25亿元&#xff0c;同比增长10%&#xff1b;非国际通用会计准则下的净利润为449.21亿元&#xff0c;同比增长39%。此前两个季度&#xff0c;腾讯的营收、净利润增速…

DependencyProperty.Register:wpf 向别的xaml传递参数

一.使用背景&#xff1a;在A.xaml中嵌入B.xaml&#xff0c;并且向B.xaml传递参数。 函数介绍&#xff1a; public static DependencyProperty Register(string name, Type propertyType, Type ownerType );name&#xff08;string&#xff09;&#xff1a; 依赖属性的名称。在…

Tekton — 通过tekton-operator部署tekton组件

文章目录 版本信息部署准备安装卸载tekton组件 Tektoncd Operator 作为一个 Kubernetes 的扩展&#xff0c;可以方便快捷地在 Kubernetes 集群上安装、升级和管理 Tekton Pipelines、Dashboard、Triggers 等组件。 那么本篇文章介绍在K8S集群中如何通过tekton-operator部署Tekt…

SAE 2.0,让容器化应用开发更简单

云布道师 云原生这个概念从提出&#xff0c;到壮大&#xff0c;再到今天的极大普及&#xff0c;始终处于一个不断演进和革新的过程中。云原生体系下应用的托管形态是随着企业应用架构在不断演进的。最早的应用大多是集中式、单体式的&#xff0c;应用通过优雅的分层来实现领域…

七牛云产品使用介绍之Kodo篇

前不久刚参加完七牛云举办的第二届1024创作节&#xff08;虽然只是我单方面的被各方大佬碾压&#xff09; 赛题是网页短视频应用开发&#xff0c;要求作品中使用七牛云的相关产品&#xff0c;于是我决定分享下七牛云产品的使用&#xff08;这么好用的产品很难忍住不想分享的心情…

易货:一种新型的商业模式

随着经济的发展和社会的进步&#xff0c;人们对于交易的需求和方式也在不断变化。传统的商业模式已经无法满足人们对于多元化、个性化、高效的需求。在这样的背景下&#xff0c;易货模式逐渐走进人们的视野&#xff0c;成为一种新型的商业模式。 易货模式是一种以物换物的交易方…

提升企业人效,从精细化考勤管理开始

过去&#xff0c;许多企业提到考勤管理&#xff0c;只能关联到打卡、请假、算薪这些简单的事务性流程。随着越来越多企业希望通过数字化转型来提升运营效率&#xff0c;实现精细化人员管理。考勤数据的作用也不再仅限于算薪&#xff0c;而是成为了企业分析人效的关键因子。因此…

产品经理的具体工作职责有什么?

产品经理是现代企业中非常重要的一种职位&#xff0c;其工作职责也非常广泛和复杂。产品经理需要在市场、用户、技术等多个方面进行综合考虑&#xff0c;为企业开发出具有竞争力的产品&#xff0c;从而推动企业的发展。下面我们将详细介绍产品经理的具体工作职责。 一、市场调研…

如何正确复制CSDN文章到自己的博客

1.csdn 文章页面&#xff0c;按f12打开浏览器开发者工具 2.按ctrl f 找 "article_content" 3.在该元素源代码上右键 “Copy”->“Copy element” 4.新建一个txt文件,把你粘贴的东西复制进去,然后再把文件名的后缀改为html,然后打开html文件,把里面的内容ctrlA全部…

PHP如何持续监听Redis的消息订阅并推送到前端?

PHP如何持续监听Redis的消息订阅并推送到前端&#xff1f; 概述: 在许多Web应用程序中&#xff0c;实时推送消息是很常见的需求。当我们需要向前端实时发送消息时&#xff0c;往往会使用轮询或长轮询的方式去获取最新数据。但这种方式对服务器资源的消耗较大&#xff0c;同时响…

Linux 中 .tar 和 tar.gz 的区别

1、前言 有时候你会发现&#xff0c;即便是有些拥有 3 年左右工作经验的运维或开发工程师对 .tar 和 .tar.gz 的区别并不是很清楚。.tar 和 .tar.gz 是在 Linux 系统中用于打包和压缩文件的两种常见格式。它们之间的主要区别在于压缩算法和文件扩展名。 2、区别 .tar .tar 是…

电商领域的三大沉疴难题?实在智能RPA来帮你药到病除!

在电商市场规模迅速扩大的当下&#xff0c;厂家们为了保持自身的竞争力&#xff0c;纷纷走上了数智化转型的道路&#xff0c;明白学会使用自动化利器才是制胜之道。 如今从产业的生产线到运营商、物流运输、商品售前、商品售后&#xff0c;实在RPA在电商平台的应用已经十分广泛…

Less精简直接上手,纯干货教程

目录 介绍 安装插件 入门使用测试 ​编辑 less变量 介绍 less作为一门CSS扩展语言&#xff0c;也就是说CSS预处理器。&#xff08;Leaner Style Sheets&#xff09;简称less&#xff0c;它只不过是为css新增这些的功能&#xff0c;比如说&#xff1a;变量、函数、作用域等等…

java springboot测试类鉴定虚拟MVC运行值与预期值是否相同

好 上文java springboot在测试类中构建虚拟MVC环境并发送请求中 我们模拟的MVC环境 发送了一个请求 我们这次需要 对比 预期值和运行值是否一直 这里 我们要用一个 MockMvcResultMatchers 他提供了非常多的校验类型 例如 请求有没有成功 有没有包含请求头信息 等等 这里 我们做…

焦炉加热系统简述

烟道吸力 焦炉负压烘炉分烟道的吸力会影响立火道温度&#xff0c;具体影响因素如下&#xff1a; 烟道吸力过大会导致热量被抽走&#xff0c;使立火道温度降低。烟道吸力不足会导致烟气在烘炉内停留时间过长&#xff0c;使热量无法充分利用&#xff0c;也会导致立火道温度降低…