本文概览:介绍InheritableThreadLocal和InheritableThreadLocal了应用场景。

0 概览

ThreadLocal、InheritableThreadLocal和InheritableThreadLocal比较:

  • ThreadLocal,线程独享这个变量。
  • InheritableThreadLocal  创建子线程(new Thread)时,在子线程中 共享 父线程的threadlocal。—-谁创建 子线程, set谁的thredlocal。
  • TransmittableThreadLocal 在使用线程池时,线程池的work线程 共享 调用者线程的threadlocal。    —-谁调用 work线程 ,set 谁的threadlocl

JDK的InheritableThreadLocal类可以完成父线程到子线程的值传递。但对于使用线程池等会池化复用线程的组件的情况,线程由线程池创建好,并且work线程是池化起来反复使用的;这时父子线程关系的ThreadLocal值传递已经没有意义,应用需要的实际上是把 任务提交给线程池时的ThreadLocal值传递到 任务执行时

注意:线程池有私有和共享情况,私有时(一个线程独享此线程池,即在这个线程中new的线程池),InheritableThreadLocal也能满足,但是一般线程池是服务的共享资源。

1 ThreadLocal

关于ThradLocal使用可以参考。

Threadlocal的实例

如下是一个简单实现,在介绍InheritableThreadLocal和TransmittableThreadLocal都会使用这个context。

1、定义context

2、定义ContextHolder

3、测试

执行结果如下:

存在一个问题是在子线程中没有获取到context的值。此时引入了InheritableThreadLocal。

2  InheritableThreadLocal

由上面例子可以知道ThradLocal的变量不能传给子线程,此时JDK提供了InheritalbeThreadLocal,如下:

此时再执行上面的TestContextHolder#main函数,输出结果如下,发现在子线程中获取到这个ThradLocal的变量值。

19:53:23.557 [pool-1-thread-1] INFO concurrent.TreadPoolContextHolder – task0,productNo=910000032

19:53:23.557 [main] INFO concurrent.TreadPoolContextHolder – main context,productNo=910000032

此时解决了子线程共享父线程的threadlocal数据的问题,但是使用线程池时会存在问题,即线程池的work线程无法获取调用线程的threadlocal变量。举例如下:

执行结果如下:

对于线程1和线程2,获取上下文中productNo分别为t001和t002,但是调用公用线程池中work线程的上下文是t000(这个值是创建这个work线程的 main线程设置的上下文数据)。

现在我们需要实现的时,在线程池中work线程执行时获取的上下文为 执行 该work线程的那个线程的上下文,不是 创建 worker线程的 那个线程的上下文。

3 TransmittableThreadLocal

3.1 引入TransmittableThreadLocal

除了设置ContextHolder中context为TransmittableThreadLocal类型,还需要自定义线程池。

1、设置context类型为TransmittableThreadLocal

2、修饰线程池

通过如下方式修饰线程池

具体代码如下:

执行结果为:

3.2 使用时两种方式

依赖maven

使用方式如下两种,参考官网:https://github.com/alibaba/transmittable-thread-local

1、方式1 修饰线程池 (建议)

这种方式不需要再重新实现省去每次Runnable和Callable传入线程池时的修饰,通过工具类com.alibaba.ttl.threadpool.TtlExecutors完成,有下面的方法:

  • getTtlExecutor:修饰接口Executor
  • getTtlExecutorService:修饰接口ExecutorService。常用方式
  • getTtlScheduledExecutorService:修饰接口ScheduledExecutorService

以getTtlExecutorService举例:

2、方式2 修饰runnable和callable

(1) 修饰runnable

(2)修饰callable

4 参考文献

1、TransmittableThreadLocal GitHub:https://github.com/alibaba/transmittable-thread-local

2、TransmittableThreadLocal 源码:https://www.jianshu.com/p/aab6b1e7357d

3、如何在子线程和线程池中使用 ThreadLocal 传输上下文 https://www.jianshu.com/p/4093add7f2cd

分类&标签