线程本地变量交换框架-TransmitterableThreadLocal(阿里开源)

上文 :秒级达百万高并发框架-Disruptor


TransmitterableThreadLocal介绍

    TransmitterableThreadLocal简称TTL 是阿里巴巴开源的一个框架。TransmittableThreadLocal是对Java中的ThreadLocal进行了增强和扩展。它旨在解决在线程池或异步任务调用链中,ThreadLocal无法正确传递值的问题。

TransmitterableThreadLocal源码:https://github.com/alibaba/transmittable-thread-local

754a9076972d6129c7fc57468b2aaacb.png

TransmitterableThreadLocal解决了什么问题?

正常情况下,当使用线程池或异步任务时,原始的ThreadLocal在线程切换或任务执行时无法将设置的值正确传递给子线程或后续任务。这使得在使用线程池或异步编程时,ThreadLocal的使用变得非常复杂。TransmittableThreadLocal通过在线程切换时显式地传递ThreadLocal的值,解决了上述问题。它提供了一种机制,可以自动将ThreadLocal的值从父线程传递到子线程,并确保在整个任务调用链中正确传递。

使用TransmittableThreadLocal时,您可以像使用普通的ThreadLocal一样设置和获取值,但它会自动处理值的传递。这样,即使在线程池或异步任务中,也能够正确地共享和传递ThreadLocal的值。

个人理解:其实就是原有线程池的一个加强版,解决上一个线程带给下一线程一些值传递问题。

TransmitterableThreadLocal的使用

引入jar包

<dependency><groupId>com.alibaba</groupId><artifactId>transmittable-thread-local</artifactId><version>2.14.2</version>
</dependency>

验证demo代码

demo1

package com.ttl;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.alibaba.ttl.TransmittableThreadLocal;public class MyRunnable implements Runnable {private static TransmittableThreadLocal<Integer> threadLocal = new TransmittableThreadLocal<>();@Overridepublic void run() {threadLocal.set((int) (Math.random() * 100)); // 设置当前线程的值try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("TransmittableThreadLocal value: " + threadLocal.get()); // 获取当前线程的值}
}
package com.ttl;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** @author: csh* @Date: 2023/7/8 20:37* @Description:* ttl案例,通过 线程池,将上一个线程带给下一线程。**/
public class StudyTtl {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);MyRunnable sharedRunnable = new MyRunnable();executorService.execute(sharedRunnable);executorService.execute(sharedRunnable);executorService.shutdown();}
}

结果

TransmittableThreadLocal value: 99
TransmittableThreadLocal value: 25

demo2

package com.ttl;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.alibaba.ttl.TransmittableThreadLocal;public class TransmittableThreadLocalDemo {public static void main(String[] args) {// 创建线程池ExecutorService executorService = Executors.newFixedThreadPool(2);// 创建TransmittableThreadLocal实例TransmittableThreadLocal<Integer> threadLocal = new TransmittableThreadLocal<>();// 在主线程设置值threadLocal.set(42);System.out.println("主线程 - ThreadLocal value: " + threadLocal.get());// 提交任务到线程池executorService.execute(() -> {// 打印子线程中的ThreadLocal值System.out.println("子线程 - ThreadLocal value: " + threadLocal.get());});// 关闭线程池executorService.shutdown();}
}

结果

主线程 - ThreadLocal value: 42
子线程 - ThreadLocal value: 42

TransmitterableThreadLocal的实现原理

TransmittableThreadLocal的实现原理主要依赖于Java的InheritableThreadLocal和ThreadLocal。

在Java中,InheritableThreadLocal是一个可以在父线程和子线程之间传递值的类。它通过子线程继承父线程的值,并且可以在子线程中对该值进行修改。然而,InheritableThreadLocal并不能满足在线程池或异步任务场景下的需求,因为它仅在线程创建时继承值,而在线程切换 or 任务执行后无法正确地传递值。

TransmittableThreadLocal通过扩展InheritableThreadLocal类,并重写其相关方法,实现了对ThreadLocal值传递的增强。

具体来说,TransmittableThreadLocal的实现原理如下:

在TransmittableThreadLocal中,每个ThreadLocal对象都有一个对应的Holder对象(比如TransmitterableThreadLocal.TransmitterableThreadLocalHolder),用于保存值的传递。

当主线程设置ThreadLocal值时,TransmittableThreadLocal会将值存储在Holder对象中。

当创建子线程时,TransmittableThreadLocal会使用InheritableThreadLocal的特性,将父线程中的Holder对象复制到子线程中。

在子线程中,当通过TransmittableThreadLocal获取值时,它会先检查当前线程是否有Holder对象。如果没有,则会从父线程中获取Holder对象,并拷贝一份到子线程中,以确保值的正确传递。

当父线程的ThreadLocal值发生改变时,TransmittableThreadLocal还会同步更新子线程的对应值,以保持值的一致性。

总结起来,TransmittableThreadLocal的实现机制主要通过继承InheritableThreadLocal类,重写相关方法,并使用Holder对象进行值的传递和同步更新。这样就能够在线程切换或异步任务中正确地传递ThreadLocal的值。

TransmitterableThreadLocal核心源码学习

类图

869f087c32eb93bcd3c836e9eb833d3a.png

com.alibaba.ttl.TransmittableThreadLocal实现如下

public class TransmittableThreadLocal<T> extends InheritableThreadLocal<T> {private transient ConcurrentMap<Thread, T> threadLocalValues = new ConcurrentHashMap<>();private transient ConcurrentMap<Thread, ThreadLocalMap> inheritableThreadLocals = new ConcurrentHashMap<>();@Overridepublic void set(T value) {Thread currentThread = Thread.currentThread();// 检查当前线程是否存在 ThreadLocalMap 对象,如果不存在,则创建ThreadLocalMap threadLocals = inheritableThreadLocals.get(currentThread);if (threadLocals == null) {threadLocals = new ThreadLocalMap();inheritableThreadLocals.put(currentThread, threadLocals);}// 设置当前线程的值threadLocals.set(this, value);// 存储当前线程的值threadLocalValues.put(currentThread, value);}//初始化值方法@Overrideprotected T initialValue() {return null;}//获取父类的值@Overrideprotected T childValue(T parentValue) {return parentValue;}//获取方法@Overridepublic T get() {Thread currentThread = Thread.currentThread();// 首先尝试从 threadLocalValues 获取当前线程的值T value = threadLocalValues.get(currentThread);if (value == null && !threadLocalValues.containsKey(currentThread)) {// 如果 threadLocalValues 中不存在当前线程的值,则尝试从 inheritableThreadLocals 获取ThreadLocalMap threadLocals = inheritableThreadLocals.get(currentThread);if (threadLocals != null) {value = threadLocals.get(this);}// 如果还是没有获取到值,则调用 initialValue() 方法初始化if (value == null) {value = initialValue();// 将值存储到 threadLocalValues 和 inheritableThreadLocals 中threadLocalValues.put(currentThread, value);if (threadLocals == null) {threadLocals = new ThreadLocalMap();inheritableThreadLocals.put(currentThread, threadLocals);}threadLocals.set(this, value);}}return value;}//删除当前线程的内容@Overridepublic void remove() {Thread currentThread = Thread.currentThread();threadLocalValues.remove(currentThread);ThreadLocalMap threadLocals = inheritableThreadLocals.get(currentThread);if (threadLocals != null) {threadLocals.remove(this);}}
}

其它源码可自行了解~

最后

    ttl这个框一般是用于链路跟踪技术的场景,可以将当前线程生成的一个taskid传递到下一个线程,然后由下一个线程来处者或者一些线上特殊的业务场景需要前后或多个线程依次传递的一个场景,但是建议还是通过新增字段或统一缓存比如redis这种来做这种操作,因为如果仅仅是一个线程内的,很有可能因为机器需要重启或一些未考虑到的操作,导致该操作的值丢失,而且这种耦合到你的业务代码中不太合理,特别是关于业务代码这种,如果实在没有必要或有更好的方案建议还是要考虑场景是否合适,本人就因为看过太多同学为了炫耀技术,导致项目代码维护及发现一些很难排查的线上事故~~~

参考文献:

https://segmentfault.com/a/1190000041954190?utm_source=sf-similar-article

https://github.com/alibaba/transmittable-thread-local

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

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

相关文章

【DASOU视频记录】Transformer从零详细解读

文章目录 来源transformer的全局理解位置编码多头注意力机制残差Batch NormalLayer NormalDecoder 来源 b站链接 transformer的全局理解 输入中文&#xff0c;输出英文 细化容易理解的结构&#xff0c;就是先编码&#xff0c;再解码 进一步细化的结构&#xff0c;就是多个编…

ARM异常处理详解

前言&#xff1a; 学习一门处理器最重要的就是掌握该处理器的指令集和异常处理。 异常概念&#xff1a; 处理器在正常执行程序时可能会遇到一些不正常的事件发生&#xff0c;这时处理器就要将当前的程序暂停下来转去处理这个异常的事件&#xff0c;异常处理后再返回到被异常打…

Windows下PaddleOCR用NCNN部署

1.所用到的ncnn格式的模型文件 要问这些模型哪里来的&#xff0c;请看下面提示信息: 2.查看字典函数读取方法 char* readKeysFromAssets() {std::ifstream ifs("./model/paddleocr_keys.txt");if (!ifs.is_open()){return 0;}ifs.seekg(0, std::ios_base::end);int …

以太网数据链路层相关技术(六)

目录 一、概述 二、MAC地址 2.1 概述 2.2 MAC地址的意义 三、共享介质型网络与非共享介质网络 四、VLAN技术 一、概述 在各设备之间的数据传输时&#xff0c;物理层和数据链路层是必不可少的。其中&#xff0c;物理层的通信媒介包括双绞线电缆、同轴电缆、光纤、电波以及…

1763_gcc编译c语言makefile自动生成工具的Perl实现_Linux

全部学习汇总&#xff1a; GreyZhang/g_makefile: Learn makefile from all kinds of tutorials on the web. Happy hacking and lets find an common way so we may dont need to touch makefile code any more! (github.com) 其实&#xff0c;调试完这个之后觉得之前Windows上…

docker环境部署postgres版本nacos

1、docker安装postgres 执行命令&#xff1a;docker pull postgres 拉取最新版postgres 2、查看postgres镜像是否安装成功: docker imags(查看镜像)&#xff0c;可以看到已经拉取到了最新版本 的postgres镜像 3、编辑一个docker-compose.yml文件&#xff0c;账号是postgres&a…

DynaSLAM 2018论文翻译

Dynaslam:动态场景下的跟踪、建图和图像修复 摘要-场景刚性假设是SLAM算法的典型特征。这种强假设限制了大多数视觉SLAM系统在人口稠密的现实环境中的使用&#xff0c;而这些环境是服务机器人或自动驾驶汽车等几个相关应用的目标。 在本文中&#xff0c;我们提出了一个基于ORB…

【网络安全带你练爬虫-100练】第11练:xpath快速定位提取数据

目录 一、目标1&#xff1a;使用etree解析数据 二、目标2&#xff1a;使用xpath爬取指定数据 三、目标3&#xff1a;提取指定数据 四、网络安全小圈子 一、目标1&#xff1a;使用etree解析数据 其余的不用过多介绍&#xff0c;前面的练习都给大家已经过了一遍 def get_page…

Skywalking高级使用

Skywalking高级使用 RPC调用监控Mysql调用监控Skywalking常用插件获取追踪ID过滤指定的端点告警功能Skywalking原理Open Tracing介绍 RPC调用监控 Skywalking(6.5.0)支持的RPC框架有以下几种&#xff1a; (1) Dubbo 2.5.4 -> 2.6.0 (2) Dubbox 2.8.4 (3) Apache Dubbo 2.7.…

Windows mingw64 最简易 安装配置

其实挺简单一件事 很多教程都搞复杂了 自己写一个 只需要两步 1. 下载压缩包并解压 2. 配置环境变量 (1). GitHub 下载地址 Releases niXman/mingw-builds-binaries GitHub 如果GitHub下载太慢可以来这里加速 或者用地址2 GitHub Proxy 代理加速 (ghproxy.com) (2). 下…

Vue3的使用--002

Vue3包含vue2的语法&#xff0c;学习vue3就行。 前提要求&#xff0c; 安装大于node.js15.0。 创建Vue 项目 &#xff1a; npm init Vuelastest : 这一执行将会安装并执行create-vue, 他是Vue 官方的脚手架工具。你将会看到一些Typescript 和测试支持之类的可选功能提示&…

VTK STL 体积 表面积测量 最短路径 读取中文路径

目录 开发环境&#xff1a; vtkMassProperties 三、中文路径 数据读取 开发环境&#xff1a; 系统&#xff1a;Win10 VTK&#xff1a;8.2.0 Qt&#xff1a;5.12.4 一、结构化对象 体积 面积 vtkMassProperties VTK 计算体积和面积的主要类 vtkMassProperties vtkSm…