alibaba transmittable-thread-local

寇升
2023-12-01

需求场景

ThreadLocal的需求场景即TransmittableThreadLocal的潜在需求场景,如果你的业务需要『在使用线程池等会池化复用线程的执行组件情况下传递ThreadLocal值』则是TransmittableThreadLocal目标场景。

下面是几个典型场景例子。

  1. 分布式跟踪系统 或 全链路压测(即链路打标)
  2. 日志收集记录系统上下文
  3. SessionCache
  4. 应用容器或上层框架跨应用代码给下层SDK传递信息

使用类TransmittableThreadLocal来保存值,并跨线程池传递。

TransmittableThreadLocal继承InheritableThreadLocal,使用方式也类似。相比InheritableThreadLocal,添加了

  1. copy方法
    用于定制 任务提交给线程池时 的ThreadLocal值传递到 任务执行时 的拷贝行为,缺省传递的是引用。
    注意:如果跨线程传递了对象引用因为不再有线程封闭,与InheritableThreadLocal.childValue一样,使用者/业务逻辑要注意传递对象的线程安全。
  2. protectedbeforeExecute/afterExecute方法
    执行任务(Runnable/Callable)的前/后的生命周期回调,缺省是空操作

1. 简单使用

父线程给子线程传递值。

 public static void main(String[] args) throws InterruptedException {
        
        TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
        // 在父线程中设置值
        context.set("value-set-in-parent");
        System.out.println("父线程中的数据:" + context.get());
        new Thread(()->{
           // 在子线程中获取父线程中的数据
            String value = context.get();
            System.out.println("子线程获取父线程中的数据:" + value);
        }).start();
        Thread.sleep(10000);
    }

父线程中的数据:value-set-in-parent
子线程获取父线程中的数据:value-set-in-parent

这种普通的异步子线程能正常获取父线程中的数据。

2. 保证线程池中传递值

  private static ExecutorService executorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(2));
    //这里采用TTL的实现
    private static ThreadLocal tl = new TransmittableThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {

        new Thread(()->{
            String mainThreadName = "main_01";
            tl.set(1);
            executorService.execute(() -> {
                sleep(2L);
                System.out.println(String.format("本地变量改变之前(1), 父线程名称-%s, 子线程名称-%s, 变量值=%s", mainThreadName, Thread.currentThread().getName(), tl.get()));
            });

            tl.set(2);
            executorService.execute(() -> {
                sleep(1L);
                System.out.println(String.format("本地变量改变之后(2), 父线程名称-%s, 子线程名称-%s, 变量值=%s", mainThreadName, Thread.currentThread().getName(), tl.get()));
            });




        }).start();
    }


    private static void sleep(long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

当前版本的Java API文档地址: https://alibaba.github.io/transmittable-thread-local/apidocs/

 

 Maven依赖

示例:

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

 更多文档

 

 

 类似资料: