初识TransmittableThreadLocal

大家好,我叫大鸡腿,大家可以关注下我,会持续更新技术文章还有人生感悟,感谢~

在这里插入图片描述

前言

TransmittableThreadLocal是阿里开源的一个类,主要目的是处理父子线程变量不能共用的情况。ThreadLocal是跟当前线程挂钩的,所以脱离当前线程它就起不了作用。

ThreadLocal

场景:它的应用就是比如当前用户特有的一些属性,不能跟其他线程,用户共用。

TransmittableThreadLocal

场景:就是父子线程或者不同线程需要共用一些变量。举个例子:之前在肥朝哥群里,肥大一直叼胃口,因为全链路日志是自研的嘛,没有sleuth等等框架的支持,所以像MDC这些全局变量,在多线程里头就失效了。

有人觉得打印log不就完事了吗?

链路日志就是为了把请求参数,整个链路打印出来,看出性能问题,以及报错的前因后果。

有了TransmittableThreadLocal就不破自解了。

TransmittableThreadLocal

源码走起

在这里插入图片描述
比较关键就是在get,set方法里头。我们看下addValue方法是哪路神仙。

在这里插入图片描述
如果当前holder没有储存当前线程,那么就把当前线程set到这个holder里头,我们再看下holder是何方神圣。

在这里插入图片描述
其实是InheritableThreadLocal,里头包裹一个Map,类型是TransmittableThreadLocal。

这个有什么用呢?

TransmittableThreadLocal跟InheritableThreadLocal的区别?

在这里插入图片描述
InheritableThreadLocal解决父子线程的问题,它是在线程创建的时候进行复制上下文的。那么对于线程池的已经创建完了就无从下手了,所以在线程提交的时候要进行上下文的复制。这就是TransmittableThreadLocal想要解决的问题。

在这里插入图片描述

任务提交给线程池时的ThreadLocal值传递过程

1.TtlRunnable
在这里插入图片描述
在创建的时候,copiedRef会将上下文保存起来。

private final AtomicReference<Map<TransmittableThreadLocal<?>, Object>> copiedRef;

2.copy
在这里插入图片描述
这一块就是解释上面holder的作用,将值取出来赋值给copiedRef

3.run
在这里插入图片描述
在提交的时候进行复制上下文。

4.backupAndSetToCopied
在这里插入图片描述
到这里就完成上下文ThreadLocal的值进行复制了。

maven

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

demo

import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.TtlRunnable;

import java.util.concurrent.TimeUnit;

public class TtlSample1 {

    static ThreadLocal<String> TTL = new TransmittableThreadLocal<>();

    public static void main(String[] args) throws Exception {
        new Thread(() -> {
            // 在父线程中设置变量
            TTL.set("throwable");
            new Thread(() -> {
                methodFrame1();
            }).start();
            try {
                TimeUnit.SECONDS.sleep(Long.MAX_VALUE);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

    private static void methodFrame1() {
        methodFrame2();
    }

    private static void methodFrame2() {
        System.out.println(TTL.get());
    }
}

他会打印throwable,如果是ThreadLocal TTL = new ThreadLocal<>()的话,返回的是null。

解读
其实上面是InheritableThreadLocal父子线程起作用

ExecutorService executorService = Executors.newCachedThreadPool();
// 额外的处理,生成修饰了的对象executorService
        executorService = TtlExecutors.getTtlExecutorService(executorService);

        TransmittableThreadLocal<String> context = new TransmittableThreadLocal<String>();
        context.set("value-set-in-parent");
        Runnable task = new Runnable() {
            @Override
            public void run() {
                System.out.println(context.get());
            }
        };
        executorService.submit(task);

针对线程池,需要使用TtlExecutors进行改造。

官网文档

参考博客

  • 16
    点赞
  • 119
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值