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

这篇具有很好参考价值的文章主要介绍了线程本地变量交换框架-TransmitterableThreadLocal(阿里开源)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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


TransmitterableThreadLocal介绍

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

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

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

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<>();

    @Override
    public 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核心源码学习

类图

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

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<>();

    @Override
    public 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);
    }
    //初始化值方法
    @Override
    protected T initialValue() {
        return null;
    }
    //获取父类的值
    @Override
    protected T childValue(T parentValue) {
        return parentValue;
    }
    //获取方法
    @Override
    public 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;
    }
    //删除当前线程的内容
    @Override
    public 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文章来源地址https://www.toymoban.com/news/detail-542661.html

到了这里,关于线程本地变量交换框架-TransmitterableThreadLocal(阿里开源)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [线程/C++]线程同(异)步和原子变量

    C++11中增加了线程以及线程相关的类,支持了并发编程,提高了编写的多线程程序的可移植性 C++11中提供的线程类叫做 std::thread ,基于这个类创建一个新的线程非常的简单,只需要提供线程函数或者函数对象即可,并且可以同时指定线程函数的参数。 以下了解以下常用API 构

    2024年02月12日
    浏览(37)
  • JS 变量保存为本地json文件,读取本地json文件为变量

    一、变量保存为本地json文件: 第一步:把返回的数据转成json格式                  var content = json.stringify(data); 第二步:把转成blob这种格式                var blob = new blob([content], {type: \\\"text/plain;charset=utf-8\\\"}); 第三步:调用保存 saveas  和文件名字               

    2024年02月08日
    浏览(59)
  • 华为交换机本地查看登录和操作日志

    目录 1、问题 2、解决 3、查看方法 4、为什么华为S系列交换机logbuffer 不展示用户登录和操作命令日志? 4、如何配置将登录日志和操作日志输出到logbuffer 华为S系列交换机默认在logbuffer和trapbuffer中无法查看到设备登录日志和操作命令日志 可用在日志log.log文件中查看 1)切换到

    2024年02月05日
    浏览(37)
  • 【探索Linux】—— 强大的命令行工具 P.21(多线程 | 线程同步 | 条件变量 | 线程安全)

    在上一篇文章中,我们详细探讨了多线程编程的基础概念,包括线程互斥、互斥锁以及死锁和资源饥饿等问题。我们了解到,在多线程环境下,为了防止数据竞争和保证程序的正确性,需要采用一定的同步机制来协调线程之间的执行顺序。本篇文章将继续深入探讨多线程编程

    2024年02月05日
    浏览(44)
  • ThreadLocal:线程中的全局变量

    最近接了一个新需求,业务场景上需要在原有基础上新增2个字段,接口新增参数意味着很多类和方法的逻辑都需要改变,需要先判断是否属于该业务场景,再做对应的逻辑。原本的打算是在入口处新增变量,在操作数据的时候进行逻辑判断将变量进行存储或查询。 如果全链

    2024年02月10日
    浏览(40)
  • 多线程——条件变量的概念和实现

    条件变量,也称条件锁,是利用线程间共享的全局变量进行同步的一种机制, 主要包括两个动作: 1)一个线程等待\\\"条件变量的条件成立\\\"而挂起; 2)另一个线程使\\\"条件成立\\\"(给出条件成立信号)条件的检测是在互斥锁的保护下进行的如果一个条件为假,一个线程自动阻塞

    2023年04月13日
    浏览(56)
  • 阿里云服务器安装asterisk开源sip软交换服务器

    阿里云服务器安装asterisk开源sip软交换服务器 1、使用./contrib/scripts/install_prereq install自动安装依赖环境,此处是重要步骤。 2、版本的问题 centos版本:CentOS Linux release 7.5.1804 (Core) asterisk版本:16.0.0 当5060不能监听的时候更换版本 3、启动后的报错不需要理会,非必要模块会拒绝

    2024年02月06日
    浏览(61)
  • 【Java并发编程】变量的线程安全分析

    1.成员变量和静态变量是否线程安全? 如果他们没有共享,则线程安全 如果被共享: 只有读操作,则线程安全 有写操作,则这段代码是临界区,需要考虑线程安全 2.局部变量是否线程安全 局部变量是线程安全的 当局部变量引用的对象则未必 如果给i对象没有逃离方法的作用

    2024年02月08日
    浏览(53)
  • 线程同步-信号量-互斥量-条件变量

    线程同步其实实现的是线程排队。 防止线程同步访问共享资源造成冲突。 多个线程访问共享资源的代码有可能是同一份代码,也有可能是不同的代码;无论是否执行同一份代码,只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步。 1. 问题 同一个进程

    2023年04月16日
    浏览(36)
  • 【Linux】Linux环境变量的理解 --- 命令行参数、shell子进程、环境变量、本地变量…

    加油布鲁斯,你能行的! 1. 我们平常所用的Linux指令其实也是可执行程序,和我们自己写的二进制程序没什么两样,那么为什么在执行自己的程序的时候需要加上./,而执行这些系统提供的指令(可执行程序),不需要加上./呢? 2. 要执行一个程序或者指令,必须先找到这个

    2024年01月16日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包