TransmittableThreadLocal 原理分析

前言

注:在看此篇文章前,你需要了解 ThreadLocal、InheritableThreadLocal 的原理。


这里先总体的介绍TransmittableThreadLocal (下文以 ttl 作为简称)的原理再去分析一些核心的源码,旨在先有个整体的认识,再去详细了解源码。

整体介绍

复制父线程的 ttl 到 TtlRunnable

由于InheritableThreadLocal是新建线程时复制父线程的本地变量到子线程,在线程池中由于线程只创建一次,因此无法复制新增的本地变量。
ttl 照着这个思路去找替代方案,在新建线程任务(Runnable)时将这些本地变量放到另一个类的属性字段中保存,这个类就是 TtlRunnable
下图的 holder 是一个 InheritableThreadLocal,存的是当前线程的一个 WeakHashMap key 为 ttl 对象 value 为 null,在这里可以暂时先忽略,后续再详细介绍。
复制父线程 ttl

将 TtlRunnable 保存的 ttl 复制到子线程

在执行 TtlRunnablerun() 方法时,再将属性中保存的值通过 TransmittableThreadLocal#set() 方法复制到子线程的 holder 中。需要注意的是 set() 方法并不只复制到 holder,还调用 super.set() 方法,这样相当于在子线程执行一次 ThreadLocal.set(),那么子线程就复制了父线程的本地变量。
子线程 ttl

子线程如何访问值

通过上一步,已完成从父线程将 ttl 复制到子线程,那就跟 InheritableThreadLocal 类似了,通过 get() 方法就能拿到当前子线程在父类中同一个 ttl 对象对应的值。

小结

父线程通过在新建线程任务时,将父线程所有的 ttl 先保存到 TtlRunnable 对象中,在运行任务时,再将 TtlRunnable 中的值再复制到子线程中,这样子线程就能够访问父线程中同一个 ttl 对象对应的值;这里的话如果不明白没关系,也是先给个整体的框架先了解下,后面再细分析一波就懂了。
需要注意的是,上面的步骤没有提到子线程 holder 的备份与恢复。

详细分析

我们以下面这个例子进行分析,下面代码演示了 TransmittableThreadLocal 的一种基本用法:

public static void main(String[] args) {
   
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    TransmittableThreadLocal<String> ttl = new TransmittableThreadLocal<>();
    // 父线程设置值
    ttl.set("法外狂徒张三");
    // 需要使用 TtlRunnable 包装线程任务 Runnable,完成复制
    Runnable ttlRunnable = TtlRunnable.get(() -> {
   
        // 获取同一个 ttl 对象在父子线程中的值是否一致
        String value = ttl.get();
        System.out.println(value);
    });

    executorService.submit(ttlRunnable);
    executorService.shutdown();
}

现在先介绍下刚才说到的 holder:

private static final InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>> 
holder =
        new InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>>() {
   
            @Override
            protected WeakHashMap<TransmittableThreadLocal<Object>, ?> initialValue() {
   
                return new WeakHashMap<TransmittableThreadLocal<Object>, Object>();
            }

            @Override
            protected WeakHashMap<TransmittableThreadLocal<Object>, ?> childValue(WeakHashMap<TransmittableThreadLocal<
Java 中,线程之间的变量传递是一件比较复杂的事情,因为线程之间是相互独立的,每个线程都有自己的栈空间和变量存储空间。在多线程编程中,我们经常需要在线程之间传递某些变量或者数据,这就需要使用一些特殊的技术来实现。 其中一种技术就是使用 TransmittableThreadLocalTTL)类,它可以让我们在多个线程之间传递变量,而且还可以保证变量的值在每个线程中都是唯一的。 TTL 是一个线程局部变量的扩展,它可以让我们在一个线程中创建一个变量,并且在任何一个子线程中都能够访问到这个变量的值。而且,当子线程结束时,TTL 会自动回收这个变量。 下面是一个使用 TTL 的示例代码: ``` import com.alibaba.ttl.TransmittableThreadLocal; public class Demo { private static TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>(); public static void main(String[] args) { // 在主线程中设置值 threadLocal.set("value set in main thread"); // 创建子线程并启动 Thread thread = new Thread(() -> { // 在子线程中获取值 String value = threadLocal.get(); System.out.println("value in sub thread: " + value); }); thread.start(); } } ``` 在这个示例代码中,我们首先创建了一个 TTL 对象 threadLocal,然后在主线程中设置了一个值,接着创建了一个子线程,并在子线程中获取了这个值。当子线程结束时,TTL 会自动回收这个变量。 TTL原理比较简单,它使用了 Java 中的 InheritableThreadLocal 类来实现。当我们在主线程中创建了一个 TTL 变量时,它会将这个变量存储到 InheritableThreadLocal 中。当我们创建子线程时,子线程会继承主线程的 InheritableThreadLocal 对象,并且会在自己的线程空间中创建一个新的 TTL 变量,这个变量的值会从主线程中的变量中拷贝过来。当子线程结束时,TTL 会自动回收这个变量。 总的来说,TTL 是一个非常方便的工具,它可以让我们在多个线程之间传递变量,而且还能够保证变量的值在每个线程中都是唯一的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值