并发编程模式 – TransmittableThreadLocal解决父线程与线程池的共享变量拷贝

  • Post author:
  • Post category:其他


InheritableThreadLocal虽然能解决父子线程中的对象拷贝问题,并且自己再重新childValue方法还可以实现深拷贝。但是大多数情况下我们是使用的自定义线程池,而不是方法执行过程中再去创建线程。还好阿里提供了TransmittableThreadLocal解决该问题,需要引入依赖包

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

先来一个demo,还是使用上一篇博客中InheritableThreadLocal不能解决的问题,如下:

static ThreadPoolExecutor executorService = (ThreadPoolExecutor)Executors.newFixedThreadPool(5);

static {
    executorService.prestartAllCoreThreads();
}

public static void main(String[] args) throws InterruptedException {
    TransmittableThreadLocal<String> itl = new TransmittableThreadLocal<>();
    itl.set("kevin-2");

    // 使用TtlRunnable或TtlCallable包装原生回调方法
    executorService.execute(Objects.requireNonNull(TtlRunnable.get(() -> {
        System.out.println("InheritableThreadLocal ThreadPoolExecutor by TtlRunnable:" + itl.get());
    })));

    // 使用包装TtlExecutors包装原生的ThreadPoolExecutor
    // 1、getTtlExecutor:修饰接口Executor
    // 2、getTtlExecutorService:修饰接口ExecutorService
    // 3、getTtlScheduledExecutorService:修饰接口ScheduledExecutorService
    Executor ttlExecutor = TtlExecutors.getTtlExecutor(executorService);
    ttlExecutor.execute(() -> {
        System.out.println("InheritableThreadLocal ThreadPoolExecutor by TtlExecutors:" + itl.get());
    });

    Thread.sleep(10000);
}
InheritableThreadLocal ThreadPoolExecutor by TtlRunnable:kevin-2
InheritableThreadLocal ThreadPoolExecutor by TtlExecutors:kevin-2

可见拿到了值,并且提供了对原生 ThreadPoolExecutor、Runnable、Callable的支持。只是将原对象进行包装即可,非常的方便。




使用场景:


1、分布式跟踪系统

2、应用容器或上层框架跨应用代码给下层SDK传递信息

3、日志收集记录系统上下文



4、


之前自己在项目上,在Tomcat线程池的线程中,使用自定义的线程池处理并行任务时,想在主线程中将入参(中途不会进行修改入参)放入ThreadLocal或其子类中,在并行任务的线程池中获取参数,但是发送拿不到。



5、


也是相同的场景,只是需要在子方法中获取父线程是否已经开始事务,以处理子线程中的事务问题,同样也是拿不到




项目实例:


当我在项目中使用 Java8的工具处理线程任务时,由于是自行封装的回调函数,还以为在线程池任务中也是不能获取到任务。结果是因为自己在初始化TransmittableThreadLocal时使用了设置初始化值,如下:

// 这样线程池中拿到的也是空数据
private static final TransmittableThreadLocal THREAD_LOCAL = TransmittableThreadLocal.withInitial(() -> null)

项目实例如下:



CompletableFuture.supplyAsync(回调函数, 线程池对象ThreadPoolExecutor);



版权声明:本文为it_lihongmin原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。