ThreadLocal父子线程、线程池数据传递解决

       多线程并发数据访问,确保数据安全至关重要,常用保证数据安全的方法有对代码synchronized锁、Lock锁,以及基于CAS的原子类,这些都是通过数据共享保障数据安全的,今天聊一聊另一种方案ThreadLocal线程副本,实现线程间的数据隔离,达到数据安全的目标。

一、ThreadLocal数据共享

       ThreadLocal是线程变量,ThreadLocal中填充的线程变量是当前线程,该变量对其他线程而言是隔离的,ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程只可以访问自己内部的副本变量。

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

          每个线程都维护了自己的一个 TreadLocalMap

1、ThreadLocal数据隔离的案例

public static class  Data{private final ThreadLocal<String>  threadLocalData  = ThreadLocal.withInitial(() -> "");public void  warpInfo(String prefix){// 给当前线程变量设置值threadLocalData.set(prefix+"-"+threadLocalData.get());}public  String  getInfo(){/// 获取当前线程变量return  threadLocalData.get();}public  void   clearInfo(){/// 变量使用完后一定要释放,原因有二:// 1、ThreadLocalMap的key是WeakReference<ThreadLocal<?>> 弱引用,当发生gc时候,key被回收,而value是强引用为无法被回收,造成整个threadLocalMap变量无法回收,最终引起内存泄露;// 2、在使用线程池的时候,线程复用,或造成线程变量覆盖,影响正常业务threadLocalData.remove();}}
    private final static   ExecutorService POOL = Executors.newFixedThreadPool(3);public  static void main(String[] args) {Data data = new Data();for(int i=0;i< 8;i++){POOL.execute(() -> {try {data.warpInfo("subThread");System.out.println(Thread.currentThread().getName()+"    data=> "+data.getInfo());} finally {data.clearInfo();}});}

      执行结果:

2、ThreadLocal父子线程数据传递问题

       先演示现象

   Data data = new Data();data.warpInfo("mainThread");POOL.execute(()->{System.out.println("111->info= "+ data.getInfo());data.warpInfo("subThread");System.out.println("222-info= "+data.getInfo());});

      不出意外,第一个输出是mainThread-,第二个输出是mainThread-subThread-,但是实际输出确出现意外了

        为什么会出现这个现象,这是因为在子线程和主线程之间是无法传递数据的,这更加印证了ThreadLocal具有线程隔离的作用。但是有时候确实存在需求需要线程间传递数据,并且还要保证线程安全。为了解决这一问题,官方推出了InheritableThreadLocal专门应对此种情况。

二、InheritableThreadLocal主线程子线程间数据传递

         InheritableThreadLocal是ThreadLocal的子类,通过Thread类维护inheritableThreadLocals变量,在createInheritedMap的时候获取了读线程的变量值

        改造Data类,直接将ThreadLocal替换成InheritableThreadLocal

 private final  InheritableThreadLocal<String>  threadLocalData =   new InheritableThreadLocal<>();

        执行结果,可以看到主线线程的变量值在子线程中可以正常取到。

三、TransmittableThreadLocal线程池线程之间数据传递

         不乏存在线程池内部线程之间需要实现数据传递,针对此种需求,阿里的开源工具TransmittableThreadLocal可以有效解决此类问题。

          先看下问题现象

        InheritableThreadLocal<String>  threadLocal = new InheritableThreadLocal<>();threadLocal.set("main-thread");System.out.println(Thread.currentThread().getName()+" get local data  start ===> "+threadLocal.get());ExecutorService pool = Executors.newFixedThreadPool(3);pool.execute(()-> System.out.println(Thread.currentThread().getName()+" get local data ===> "+threadLocal.get()));sleep(1);threadLocal.set("main-thread-new");System.out.println(Thread.currentThread().getName()+" get local data end ===> "+threadLocal.get());pool.execute(()-> System.out.println(Thread.currentThread().getName()+" get local data ===> "+threadLocal.get()));sleep(Integer.MAX_VALUE);

        线程池里面线程执行第二次打印的结果如果是main-thread-new,那么InheritableThreadLocal

或许具备线程池中传递线程变量的能力,看下执行结果并不理想

         线程池中第二次获取主线程修改后的变量是不可见的。解决这个问题只需要稍微改造,引入

TransmittableThreadLocal即可:

        TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();threadLocal.set("main-thread");System.out.println(Thread.currentThread().getName()+" get local data  start ===> "+threadLocal.get());ExecutorService  pool = TtlExecutors.getTtlExecutorService( Executors.newFixedThreadPool(1));pool.execute(()-> System.out.println(Thread.currentThread().getName()+" get local data ===> "+threadLocal.get()));sleep(1);threadLocal.set("main-thread-new");System.out.println(Thread.currentThread().getName()+" get local data end ===> "+threadLocal.get());pool.execute(()-> System.out.println(Thread.currentThread().getName()+" get local data ===> "+threadLocal.get()));sleep(Integer.MAX_VALUE);

        至此完美解决线程变量线程池线程传递。 

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Docker 从入门到精通全攻略

一、Docker 初印象 Docker 诞生于 2013 年&#xff0c;由 dotCloud 公司发起&#xff0c;最初是一个公司内部项目。其诞生背景源于程序员们苦于应用部署环境的复杂性&#xff0c;开发、测试、部署过程中各种库的依赖纷繁复杂&#xff0c;版本差异以及测试环境与部署环境不一致等…

WordPress设置自动更新CSS版本号

WordPress 通常会在引用 CSS 文件时添加版本号参数&#xff08;?verx.x.x&#xff09;。如果版本号未更新&#xff0c;浏览器可能继续加载旧的文件。 解决方法&#xff1a;确保你在 functions.php 文件中正确加载了 CSS 文件&#xff0c;并动态更新版本号。例如在functions.p…

达梦 DG

监视器 switchover 关于达梦DG switchover的细节&#xff0c;以下是一些关键步骤和注意事项&#xff1a; • 切换前检查确认&#xff1a; • 确认数据库版本和DG架构&#xff0c;包括IP信息及切换角色前后的情况。 • 检查DG切换方式&#xff0c;是switch over还是fail ove…

c#基本数据类型占用字节长度/取值范围/对应.net类型

具体前往&#xff1a;c#基本数据类型占用字节数/取值范围/包装类-各基本类型.net类型,占用bit位数,默认值及取值范围

多品牌NVR管理工具/设备EasyNVR多个NVR同时管理支持RTSP接入

在当今数字化浪潮席卷全球的背景下&#xff0c;视频监控行业正经历着前所未有的变革。传统的本地录像存储模式正逐步向云端集中管理转型&#xff0c;这一技术的飞跃不仅极大地提升了监控效率与安全性&#xff0c;更为各行各业的智能化管理开辟了新路径。在这一转型过程中&#…

初学者指南:知识库问答(KBQA)多跳路径的核心与应用

初学者指南&#xff1a;知识库问答&#xff08;KBQA&#xff09;多跳路径的核心与应用 知识库问答&#xff08;Knowledge Base Question Answering, KBQA&#xff09;旨在利用结构化知识库&#xff08;如Wikidata、Freebase&#xff09;回答自然语言问题。在实际应用中&#x…

利用Python爬虫获取淘宝店铺详情

在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。对于电商平台&#xff0c;尤其是淘宝这样的大型电商平台&#xff0c;店铺详情数据的获取和分析对于商家来说至关重要。它不仅可以帮助商家了解市场趋势&#xff0c;还可以优化营销策略&#xff0c;提升销售业绩。本文…

卡尔曼滤波学习资料汇总

卡尔曼滤波学习资料汇总 其实&#xff0c;当初的目的&#xff0c;是为了写 MPU6050 的代码的&#xff0c;然后不知不觉学了那么多&#xff0c;也是因为好奇、感兴趣吧 有些还没看完&#xff0c;之后笔记也会同步更新的 学习原始材料 【卡尔曼滤波器】1_递归算法_Recursive P…

【HCIP]——OSPF综合实验

题目 实验需求 根据上图可得&#xff0c;实验需求为&#xff1a; 1.R5作为ISP&#xff1a;其上只能配置IP地址&#xff1b;R4作为企业边界路由器&#xff0c;出口公网地址需要通过PPP协议获取&#xff0c;并进行CHAP认证。&#xff08;PS&#xff1a;因PPP协议尚未学习&#…

MarkDown笔记记录app——待更新

1&#xff0c;语雀&#xff1a; 容易整理&#xff0c;直接上手&#xff0c;直接导出到csdn或者是github中 2&#xff0c;notion&#xff1a;注意及时清理 平时主要资料整理部分&#xff0c;注意每个page里面包含子page不能超过5MB&#xff0c; 所有的老资料笔记需要导出为htm…

vxe-table 4.9+ 实现在表格列中直接拖拽排序,列拖拽排序

Vxe UI vue vxe-table v4.9 实现在表格列中直接拖拽排序&#xff0c;列拖拽排序 安装 npm install vxe-pc-ui4.3.3 vxe-table4.9.0main.js // ... import VxeUI from vxe-pc-ui import vxe-pc-ui/lib/style.css import VxeUITable from vxe-table import vxe-table/lib/styl…

《勇者斗恶龙3:HD-2D重制版》找幽灵船攻略分享

《勇者斗恶龙3&#xff1a;HD-2D重制版》中的幽灵船是游戏里非常独特的一个区域&#xff0c;而想要找到幽灵船的话还是比较麻烦的&#xff0c;首先是听到关于幽灵船在世界海域上航行的传闻&#xff0c;包括在海盗巢穴中&#xff0c;但幽灵船的出现有一些具体条件。 勇者斗恶龙3…

《通往人工智能深度学习专家之路:全面解析学习路线图》

《通往人工智能深度学习专家之路&#xff1a;全面解析学习路线图》 一、人工智能深度学习简介1.1 人工智能与深度学习的关系1.2 深度学习的应用领域1.3 深度学习的重要性 二、深度学习路线图总览2.1 学习路线图的结构2.2 各阶段学习目标与重点 三、深度学习基础阶段3.1 数学基础…

力扣题解661 图片平滑器

题目&#xff08;简单&#xff09; 图像平滑器 是大小为 3 x 3 的过滤器&#xff0c;用于对图像的每个单元格平滑处理&#xff0c;平滑处理后单元格的值为该单元格的平均灰度。 每个单元格的 平均灰度 定义为&#xff1a;该单元格自身及其周围的 8 个单元格的平均值&#xff0c…

基于SpringBoot的“致远汽车租赁系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“致远汽车租赁系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 致远汽车租赁系统总体功能模块图 系统首页界面…

DSP28335 DMA 官方例程解析以及拓展(一)

文章目录 概述官方例程1 内部RAM to RAM Example_2833xDMA_ram_to_ram源码解析 要点方法拓展 外部固定地址 TO RAM完整程序: 对DMA 和 DMA有关的API请看这篇文章 DSP28335 DMA API介绍 概述 本篇主要分析官方提供的28335 DMA 有关的例程 在此基础上有一定的拓展 官方例程1 内…

【Java SE】JDBC

JDBC&#xff08;Java DataBase Connectivity&#xff09;是一套用于在 Java 中操作关系型数据库的 API。它允许开发者使用统一的 Java 代码来访问不同的关系型数据库。 JDBC 的本质&#xff1a;JDBC 是由官方&#xff08;Sun 公司&#xff09;定义的一套接口规范&#xff0c;…

西电数据库课设|设计学籍管理系统

前言&#xff1a;ER图和逻辑结构图不准确&#xff0c;因为在后期实际建表的过程中有改动&#xff0c;去除了一些列和外键关系&#xff0c;但是我懒得返回去改图了&#xff0c;所以还是需要自己情况画图&#xff0c;还有学生信息我忘记加性别什么的&#xff0c;这个比较简单&…

优维HAO案例:500强旗下全牌照综合性券商CMDB平台项目

撰文&#xff1a;鹿小U / 制图&#xff1a;脾气超好 某中国500强集团旗下的HS公司&#xff0c;是一家具有一定行业影响力的综合性证券公司。在近年来的发展进程中&#xff0c;该公司坚定不移地持续推进财富管理转型工作&#xff0c;将 ETF 的财富管理以及机构经纪业务作为公司…

github进不去解决办法-误打误撞进去了

我的要求不高&#xff0c;就算麻烦&#xff0c;只要能进去就行&#xff0c;但是我找了很多的办法&#xff0c;xbox下载助手、watt Toolkit、更改host文件、fastgithub…最终还是没有用 绝望之际随便进了一个当时找的fastgithub连接 结果显示不是专用链接 然后看了该博主的文章…