首页 > 其他分享 >TransmittableThreadLocal的实现机制和原理

TransmittableThreadLocal的实现机制和原理

时间:2024-12-09 11:21:06浏览次数:4  
标签:String Thread ThreadLocal tl 线程 TransmittableThreadLocal 原理 机制

1 前言
前面我看过了 ThreadLocal的实现机制和原理 以及 InheritableThreadLocal的实现机制和原理 两种类型的 ThreadLocal,前者是普通的,后者是在前者的基础上套了一层父子线程关系,当使用后者的时候,会在线程创建的时候,浅拷贝一份父线程的变量值。那么今天空了,我来看看另外一种 ThreadLocal:TransmittableThreadLocal。
2 TransmittableThreadLocal
2.1 TransmittableThreadLocal 的认识
TransmittableThreadLocal(TTL)是阿里巴巴开源的一个 Java 库,用于解决 ThreadLocal 在多线程环境下的一些问题,尤其是在使用线程池等场景下可能出现的问题。与普通的 ThreadLocal 不同,TTL 具有以下特点:

  • 线程池透传性:在使用线程池执行任务时,TTL 可以透传 ThreadLocal 的值,确保后续线程能够正确访问前线程设置的 TransmittableThreadLocal 变量值。
  • 线程池隔离性:TTL 在多线程环境下能够确保每个线程都有独立的 TransmittableThreadLocal值,避免了线程池重用线程时可能出现的数据污染问题,比如线程池执行前从父线程继承的变量,不管是执行中变没变,下次执行任务的时候,还是会和父线程保持一致。
  • 资源自动清理:TTL 支持自动清理 TransmittableThreadLocal 值,避免了可能导致内存泄漏的问题。
  • 兼容性:TTL 兼容原生 ThreadLocal 的语法和用法,可以直接替换原生 ThreadLocal 使用,而无需修改现有代码。

2.2 TransmittableThreadLocal 的使用
TTL 通常用于需要在线程池中执行任务,并且需要在任务之间传递 ThreadLocal 值的场景。例如,在 Web 应用中,可能需要在异步任务中访问当前用户的会话信息,而使用 TTL 可以确保子线程能够正确访问父线程设置的会话信息。TransmittableThreadLocal在使用线程池等会池化复用线程的执行组件情况下,提供ThreadLocal值的传递功能(把任务提交给线程池时的ThreadLocal值传递到任务执行时),解决异步执行时上下文传递的问题。我们来简单体验一下:

// TTL
private static final TransmittableThreadLocal<Integer> tl = new TransmittableThreadLocal<>();
public static void main(String[] args) {
    // 父线程设置变量 1
    tl.set(1);
    new Thread(() -> {
        System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get()));
    }).start();
    new Thread(() -> {
        System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get()));
    }).start();
}

这么一看貌似跟我们的 ITL 没什么区别是吧。我们来看一个线程池的例子:

public class Demo {

    private static final TransmittableThreadLocal<Integer> tl = new TransmittableThreadLocal<>();
    
    private static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
            2,
            2,
            10,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(100)
    );

    public static void main(String[] args) {
        // 父线程设置变量 1
        tl.set(1);       

poolExecutor.execute(() -> { // 更改当前线程中的值 tl.set(2); System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get())); });
poolExecutor.execute(() -> { System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get())); });
poolExecutor.execute(() -> { System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get())); });
poolExecutor.execute(() -> { System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get())); }); } }

我们看普通情况下,当某个线程改变了 TTL 的值后,下次该线程执行任务的时候,TTL 的值就是改变后的了。这里需要引入一下 TTL 里的线程池,我们再看:

public class Demo {

    private static final TransmittableThreadLocal<Integer> tl = new TransmittableThreadLocal<>();

    private static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
            2,
            2,
            10,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(100)
    );
    private static final Executor ttlExecutor = TtlExecutors.getTtlExecutor(poolExecutor);

    public static void main(String[] args) {
        // 父线程设置变量 1
        tl.set(1);

        ttlExecutor.execute(() -> {
            // 更改当前线程中的值
            tl.set(2);
            System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get()));
        });
        ttlExecutor.execute(() -> {
            System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get()));
        });
        ttlExecutor.execute(() -> {
            System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get()));
        });
        ttlExecutor.execute(() -> {
            System.out.println(String.format("子线程:%s,获取值=%s", Thread.currentThread().getName(), tl.get()));
        });

    }
}

2.4 应用场景
TransmittableThreadLocal用来实现线程间的参数传递,经典应用场景如下:
(1)分布式跟踪系统 或 全链路压测(即链路打标)
(2)日志收集记录系统上下文
(3)Session级 Cache
(4)应用容器或上层框架跨应用代码给下层 SDK传递信息
2.5 ThreadLocal、InheritableThreaLocal与TransmittableThreadLocal的比较
ThreadLocal、InheritableThreadLocal与TransmittableThreadLocal在Java中都是用于处理线程局部变量的工具,但它们在使用场景和特性上有所不同。
(1)ThreadLocal
ThreadLocal是Java中一个非常重要的线程技术,它为每个线程提供了它自己的变量副本,使得线程间无法相互访问对方的变量,从而避免了线程间的竞争和数据泄露问题。适用于需要在线程内部存储和获取数据,且不希望与其他线程共享数据的场景。
(2)InheritableThreadLocal
InheritableThreadLocal是ThreadLocal的一个子类,它包含了ThreadLocal的所有功能,并扩展了ThreadLocal的功能。 允许父线程中的InheritableThreadLocal变量的值被子线程继承。当创建一个新的线程时,这个新线程可以访问其父线程中InheritableThreadLocal变量的值。
(3)TransmittableThreadLocal
TransmittableThreadLocal是阿里巴巴开源的一个框架,用于解决在使用线程池等场景下,ThreadLocal变量无法跨线程传递的问题。能够在多线程传递中保持变量的传递性,确保在父线程和子线程之间正确传递ThreadLocal变量。简单的来说就是:ThreadLocal适用于线程内部的数据存储和访问,确保数据在线程间的隔离。InheritableThreadLocal适用于需要在父线程和子线程间传递数据的场景,实现数据的继承。TransmittableThreadLocal则是为了解决在使用线程池等场景下,ThreadLocal变量无法跨线程传递的问题,实现数据的跨线程传递。

 

参考博客:https://www.cnblogs.com/kukuxjx/p/18188062

标签:String,Thread,ThreadLocal,tl,线程,TransmittableThreadLocal,原理,机制
From: https://www.cnblogs.com/jelly12345/p/18594469

相关文章

  • AS2 工作原理
    本文旨在针对AS2协议操作展开全面描述,主要内容包括:AS2是如何工作的?AS2系统的关键组成部分AS2中的信息流AS2是如何工作的?首先需要通过内部应用生成需要通过AS2传输给合作伙伴的文件。大多数此类文件是遵循ANSIX12(美国国家标准委员会)标准或者遵循UN/EDIFACT(联合国行政、......
  • FMC子卡设计原理图:FMC181-八路125Msps 14bit 直流耦合脉冲采集AD FMC子卡
    FMC181-八路125Msps14bit直流耦合脉冲采集ADFMC子卡一、板卡概述   (1) ADC采用ADI的AD9253,4通道最高125M采样率,共2片,板卡共8路输入,支持80M/105M/125Msps 采样;   (2) AD模拟输入带前端放大器和滤波电路,支持±2Vpp输入,支持直流耦合;   (3) 时钟......
  • 强化学习 不动点原理
    在强化学习中,不动点原理是一个重要的数学工具,用于求解最优策略和值函数。不动点是指一个函数$f(x)满足满足满足f(x)=x$的点,即该点在函数作用下保持不变。在强化学习中,贝尔曼最优公式是通过不动点原理来求解的,这基于Banach不动点定理,该定理指出如果一个函数是压缩......
  • 你了解什么是像素追踪吗?它是用来做什么的?它的实现原理是什么?
    像素追踪(PixelTracking)在前端开发中是一种用于收集用户行为数据的方法,它通常用于网站分析、广告转化跟踪和个性化推荐等方面。它允许网站所有者了解用户如何与他们的网站互动,例如用户点击了哪些链接、浏览了哪些页面、在每个页面停留了多长时间等等。像素追踪主要用途:网站分析......
  • 我们会经常用到ping命令,你知道它的作用和原理吗?
    ping命令是一个常用的网络诊断工具,用于测试网络连接的连通性和质量。它的主要作用是确定一台主机是否可以到达,以及到达目标主机所需的时间和网络稳定性。作用:测试连通性:检查网络上两台主机之间是否存在连接。如果能ping通,说明网络连接存在。测量延迟(Latency):测量数据......
  • 关于 MIC 音频连接器电路原理的介绍
     音频接口是连接音频设备、传输音频信号的重要组件,本节介绍3.5mm音频底座和音频插件的引脚说明以及相关电路的设计。一、常见类型3.5mm音频接口:常见于耳机、音箱、手机等设备,分三段式和四段式,小巧便携但信号质量有限。6.35mm音频接口:又称“大三芯”,用于专业音频设备,连......
  • Apollo功能及原理详解
    前言公司里面使用的配置中心是携程开源的Apollo,之前我只使用过Nacos,遂记录一下学习过程。Apollo工作原理模块介绍上图就是Apollo的总体设计,从下往上挨个分析:ConfigDB用于存储各种配置ConfigService提供配置的读取、推送等功能,服务对象是Apollo客户端,多实例,需要注册到Eure......
  • springcloud eureka原理和机制
    公司的注册中心使用的是Eureka,之前使用过ZooKeeper,大致原理应该差不多,具体细节需要进一步学习,正好之前在腾讯云开发者社区看到一篇讲得很不错的文章,转载过来方便查看。简介在微服务架构下,服务端环境通常包含多个服务,同时每个服务也是一个无状态的多实例集群。这些服务和实例一般......
  • HCIE-15 SRv6原理与配置
    目录SRv6概述IP/MPLS网络简介MPLSLDP与RSVP-TE存在的问题SR的起源与解决方案从MPLS到SRv6SRv6的技术价值SRv6原理SRv6基本概念SRv6原理简介SRv6SRH介绍SRv6Segment介绍SRv6Segment:LocatorSRv6Segment:Function&ArgumentsSRv6Segment类型介绍SRv6Segment命名规则SRv6S......
  • Redis原理—1.Redis数据结构
    大纲1.Redis的数据结构2.Redis的SDS3.Redis的链表4.Redis的字典5.Redis的跳跃表6.Redis的整数集合7.Redis的压缩列表8.Redis的对象9.Redis对象的几个关键属性10.Redis的单线程为什么这么快11.Redis的典型应用场景和说明12.Redis的相关命令说明 1.Redis的数据结构......