JUC并发工具---ThreadLocal

ThreadLocal适合用在哪些实际生产的场景中

适用场景

场景一场景二
ThreadLocal用作保存每个线程独享的对象ThreadLocal用作每个线程内需要独立保存信息以便其他方法更方便地获取该信息的场景(类似于全局变量的概念)
通常用于保存线程不安全的工具类,典型的需要使用的类就是SimpleDateFormat。每个线程内需要保存类似于全局变量的信息 (例如在拦截器中获取的用户信息)可以让不同方法直接使用避免参数传递的麻烦却不想被多线程共享 (因为不同线程获取到的用户信息不一样)
每个Thread内都有自己的实例副本,且该副本只能由当前Thread访问到并使用,相当于每个线程内部的本地变量用ThreadLocal保存一些业务内容(用户权限信息、从用户系统获取到的用户名、用户ID等)
这些信息在同一个线程内相同,但是不同的线程使用的业务内容是不相同的
在线程生命周期内,都通过这个静态ThreadLocal实例的get()方法取得自己set过的那个对象
避免了将这个对象(如user对象)作为参数传递的麻烦
import java.sql.Date;
import java.text.SimpleDateFormat;public class ThreadLocalDemo02 {public static void main(String[] args) throws InterruptedException {int numberOfThreads = 1000;for (int i = 0; i < numberOfThreads; i++) {int finalI = i;new Thread(() -> {String date = new ThreadLocalDemo02().date(finalI);System.out.println(date);}).start();}// 确保主线程等待所有子线程完成Thread.sleep(1000); // 增加等待时间以确保所有线程都能完成}public String date(int seconds) {// 获取当前时间Date date = new Date(1000 * seconds);// 格式化时间SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return simpleDateFormat.format(date);}
}
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadLocalDemo02 {public static ExecutorService threadPool = Executors.newFixedThreadPool(16);static SimpleDateFormat dateFormatHolder = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 1000; i++) {int finalI = i;threadPool.submit(new Runnable(){@Overridepublic void run() {String date = new ThreadLocalDemo02().date(finalI);System.out.println(date);}});}threadPool.shutdown();}public String date(int seconds){//获取当前时间Date date = new Date(1000*seconds);//格式化时间String s = null;// 使用synchronized会导致排队,其实也没有合理用到线程池synchronized(ThreadLocalDemo02.class) {s = dateFormatHolder.format(date);}return s;}
}
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadLocalDemo02 {public static ExecutorService threadPool = Executors.newFixedThreadPool(16);// 这个时候只创建了16个SimpleDateFormat对象public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 1000; i++) {int finalI = i;// 16个线程对应16个simpleDateFormat对象,每个线程有自己的副本,是线程安全的threadPool.submit(new Runnable(){@Overridepublic void run() {String date = new ThreadLocalDemo02().date(finalI);System.out.println(date);}});}threadPool.shutdown();}public String date(int seconds){//获取当前时间Date date = new Date(1000*seconds);//格式化时间return ThreadSafeFormatter.formatterHolder.get().format(date);}}class ThreadSafeFormatter {public static ThreadLocal<SimpleDateFormat> formatterHolder = new ThreadLocal<SimpleDateFormat>(){protected SimpleDateFormat initialValue(){return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");}};
}
public class ThreadLocalDemo03 {public static void main(String[] args) {new Service1().service1();}
}class Service1 {public void service1() {User user = new User("user1");UserContextHolder.holder.set(user);new Service2().service2();}
}class Service2 {public void service2() {User user = UserContextHolder.holder.get();System.out.println("Service2 user name: " + user.getName());new Service3().service3();}
}class Service3 {public void service3() {User user = UserContextHolder.holder.get();System.out.println("Service3 user name: " + user.getName());// 避免无限递归调用}
}class UserContextHolder {public static ThreadLocal<User> holder = new ThreadLocal<>();
}class User {private String name;public User(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

ThreadLocal是不是用来解决共享资源的多线程访问的呢

答案:不是,ThreadLocal虽然可以用于解决多线程情况下的线程安全问题,但其资源不是共享的,而是每个线程独享的。可以在initialValue中new出自己线程独享的资源,而多个线程之间,它们所访问的对象本身是不共享的,自然就不存在任何并发问题。

如果需要放到ThreadLocal中的这个对象是共享的,是被 static 修饰的即使用了ThreadLocal并不能解决线程安全问题。

对于共享的变量,如果想要保证它的线程安全,应该用其他的方法比如说可以使用synchronized或者是加锁等其他的方法来解决线程安全问题而不是使用ThreadLocal,因为这不是ThreadLocal应该使用的场景

ThreadLocal和synchronized是什么关系?

当ThreadLocal用于解决线程安全问题时,也就是把一个对象给每个线程都生成一份独享的副本的,这种场景下,ThreadLocal和synchronized都可以理解为是用来保证线程安全的手段。但是效果和实现原理不同:

  • ThreadLocal是通过让每个线程独享自己的副本,避免了资源的竞争
  • synchronized 主要用于临界资源的分配,在同一时刻限制最多只有一个线程能访问该资源

相比于ThreadLocal而言,synchronized 的效率会更低一些,但是花费的内存也更少,在这种场景下,ThreadLocal和 synchronized 都可以达到线程安全的目的

对于ThreadLocal而言,它还有不同的使用场景,比如当ThreadLocal用于让多个类能更方便地拿到我们希望给每个线程独立保存这个信息的场景下时(比如每个线程都会对应一个用户信息,也就是user对象),在这种场景下,ThreadLocal侧重的是避免传参,此时ThreadLocal和 synchronized 是两个不同维度的工具。

多个ThreadLocal在Thread中的threadlocals是怎么存储的

三者的关系

[外链图片转存中…(img-uWLWNTd1-1734882917433)]

get()方法

[外链图片转存中…(img-ggtLn05S-1734882917433)]

[外链图片转存中…(img-JVxdHiAg-1734882917433)]

[外链图片转存中…(img-GyR5f8Jt-1734882917433)]

内存泄漏:每次用完ThreadLocal都要调用remove()

内存泄漏

当某个对象不再有用的时候,占用的内存却不能被回收。

[外链图片转存中…(img-HTkqftbA-1734882917433)]

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

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

相关文章

python coding(二) Pandas 、PIL、cv2

Pandas 一个分析结构化数据的工具集。Pandas 以 NumPy 为基础&#xff08;实现数据存储和运算&#xff09;&#xff0c;提供了专门用于数据分析的类型、方法和函数&#xff0c;对数据分析和数据挖掘提供了很好的支持&#xff1b;同时 pandas 还可以跟数据可视化工具 matplotli…

第十五届蓝桥杯Scratch01月stema选拔赛—排序

排序 具体要求&#xff1a; 1). 点击绿旗&#xff0c;在舞台上出现4张点数不同的扑克牌&#xff0c;牌上的点数是随机的&#xff08;4-9点&#xff09;&#xff0c;如图所示&#xff1b; 完整题目可点击下方链接查看&#xff1a; 排序_scratch_嗨信奥-玩嗨信息奥林匹克竞赛-…

图形 3.4 延迟渲染管线介绍

延迟渲染管线介绍 B站视频&#xff1a;图形 3.4 延迟渲染管线介绍 文章目录 延迟渲染管线介绍渲染路径前向渲染渲染流程光照规则 延迟渲染渲染流程几何缓冲区 G-buffer 不同渲染路径的优劣以及特性优劣 Unity中渲染路径设置移动端优化分块延迟渲染 其他渲染路径不同路径下光源…

Qt之串口设计-线程实现(十二)

Qt开发 系列文章 - Serial-port&#xff08;十二&#xff09; 目录 前言 一、SerialPort 二、实现方式 1.创建类 2.相关功能函数 3.用户使用 4.效果演示 5.拓展应用-实时刷新 总结 前言 Qt作为一个跨平台的应用程序开发框架&#xff0c;在串口编程方面提供了方便易用…

1.gitlab 服务器搭建流程

前提条件&#xff1a; 一、服务器硬件水平 搭建gitlab服务器最低配置要求2核4G,低于这个配置的服务器运行效果很差。 gitlab官网&#xff1a;https://about.gitlab.com/ 下载地址&#xff1a;gitlab/gitlab-ce - Packages packages.gitlab.com 本机ubuntu 二、安装依赖 su…

powerhsell 初认识

免责声明 本文是学习与泷羽Sec B站课程的课程笔记内容&#xff0c;仅作学习使用&#xff0c;如有破坏网络安全的行为&#xff0c;本人概不负责 B站链接&#xff1a;https://space.bilibili.com/350329294 资源自取&#xff1a;https://pan.quark.cn/s/b2718e905db8 powerhsel…

自我维护和保养

学习运动两不误&#xff01; 本人学习过程中&#xff0c;长期久坐导致各种身体问题&#xff08;特别是腰间盘突出&#xff0c;右侧肩胛骨翘等问题&#xff01;&#xff09;&#xff0c;希望给有类似烦恼的人们带去福音&#xff01;&#xff01;&#xff01; 我的椎间盘损伤历…

详解磁盘IO、网络IO、零拷贝IO、BIO、NIO、AIO、IO多路复用(select、poll、epoll)

1、什么是I/O 在计算机操作系统中&#xff0c;所谓的I/O就是输入&#xff08;Input&#xff09;和输出&#xff08;Output&#xff09;&#xff0c;也可以理解为读&#xff08;Read&#xff09;和写&#xff08;Write)&#xff0c;针对不同的对象&#xff0c;I/O模式可以划分为…

Cursor的重磅功能Agent登场

今天看了一些介绍&#xff0c;cursor有一个新功能agent ,试用了一下非常好用。再也不用头痛地选择相关的上下文&#xff0c;真是懒人利器。 Agant特性&#xff1a; 可以自主选择上下文能够使用终端可以独立完成整个任务 赶紧介绍给大家&#xff0c;使用时&#xff0c;需要在c…

5G -- 空口关键技术

前言&#xff1a; 手机(UE)和5G基站(gNodeB)之间的空中接口 新技术的特点&#xff1a; 1、提升速率&#xff1a;大带宽、新编码、高阶调制、F-OFDM、M-MIMO 2、降低时延&#xff1a;灵活帧结构、自包含时隙、免授权调度、D2D 3、提升覆盖&#xff1a;上下行解耦、EN-DC(双连…

常用Python自动化测试框架有哪些?

随着技术的进步和自动化技术的出现&#xff0c;市面上出现了一些自动化测试框架。只需要进行一些适用性和效率参数的调整&#xff0c;这些自动化测试框架就能够开箱即用&#xff0c;大大节省了测试时间。而且由于这些框架被广泛使用&#xff0c;他们具有很好的健壮性&#xff0…

【自用】通信内网部署rzgxxt项目_01,后端pipeDemo部署(使用nssm.exe仿照nohup)

做完这些工作之后&#xff0c;不要忘记打开 Windows Server 的防火墙端口&#xff0c;8181、8081、8080、22、443、1521 做完这些工作之后&#xff0c;不要忘记打开 Windows Server 的防火墙端口&#xff0c;8181、8081、8080、22、443、1521 做完这些工作之后&#xff0c;不要…

jmeter 接口性能测试 学习笔记

目录 说明工具准备工具配置jmeter 界面汉化配置汉化步骤汉化结果图 案例1&#xff1a;测试接口接口准备线程组添加线程组配置线程组值线程数&#xff08;Number of Threads&#xff09;Ramp-Up 时间&#xff08;Ramp-Up Period&#xff09;循环次数&#xff08;Loop Count&…

Iris简单实现Go web服务器

package mainimport ("github.com/kataras/iris" )func main() {app : iris.New() // 实例一个iris对象//配置路由app.Get("/", func(ctx iris.Context) {ctx.WriteString("Hello Iris")})app.Get("/aa", func(ctx iris.Context) {ct…

tryhackme-Pre Security-HTTP in Detail(HTTP的详细内容)

任务一&#xff1a;What is HTTP(S)?&#xff08;什么是http&#xff08;s&#xff09;&#xff09; 1.What is HTTP? (HyperText Transfer Protocol)&#xff08;什么是 HTTP&#xff1f;&#xff08;超文本传输协议&#xff09;&#xff09; http是你查看网站的时候遵循的…

【C++11】可变模板参数

目录 可变模板的定义方式 参数包的展开方式 递归的方式展开参数包 STL中的emplace相关接口函数 STL容器中emplace相关插入接口函数 ​编辑 模拟实现&#xff1a;emplace接口 C11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板&#xff0c;相比 C9…

springmvc的拦截器,全局异常处理和文件上传

拦截器: 拦截不符合规则的&#xff0c;放行符合规则的。 等价于过滤器。 拦截器只拦截controller层API接口。 如何定义拦截器。 定义一个类并实现拦截器接口 public class MyInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest reque…

ECharts热力图-笛卡尔坐标系上的热力图,附视频讲解与代码下载

引言&#xff1a; 热力图&#xff08;Heatmap&#xff09;是一种数据可视化技术&#xff0c;它通过颜色的深浅变化来表示数据在不同区域的分布密集程度。在二维平面上&#xff0c;热力图将数据值映射为颜色&#xff0c;通常颜色越深表示数据值越大&#xff0c;颜色越浅表示数…

EE308FZ_Sixth Assignment_Beta Sprint_Sprint Essay 3

Assignment 6Beta SprintCourseEE308FZ[A] — Software EngineeringClass Link2401_MU_SE_FZURequirementsTeamwork—Beta SprintTeam NameFZUGOObjectiveSprint Essay 3_Day5-Day6 (12.15-12.16)Other Reference1. WeChat Mini Program Design Guide 2. Javascript Style Guid…

JVM 详解

一. JVM 内存区域的划分 1. 程序计数器 程序计数器是JVM中一块比较小的空间, 它保存下一条要执行的指令的地址. [注]: 与CPU的程序计数器不同, 这里的下一条指令不是二进制的机器语言, 而是Java字节码. 2. 栈 保存方法中的局部变量, 方法的形参, 方法之间的调用关系. 栈又…