概述
业务中经常会遇到多线程之间的上下文传递,比如自己开启子线程异步执行,或者使用线程池异步执行时,需要把token
/request
上下文传递.
手写的话,在创建子线程时需要自己包裹一下;
在使用线程池时需要对execute
方法进行包裹,比如spring
的ThreadPoolTaskExecutor
中的TaskDecorator
.
com.alibaba.ttl.TransmittableThreadLocal
就帮我们做好了这个包裹过程,称为装饰更合适一点。
需要引入maven
依赖;我当前用的是2.14.2
的版本
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.14.2</version>
</dependency>
TransmittableThreadLocal
是java.lang.InheritableThreadLocal
的子类,对线程变量copy
的时机做了调整,
java.lang.InheritableThreadLocal
是在new
的时候将调用线程的threadLocals
线程内容copy
到inheritableThreadLocals
中.
TransmittableThreadLocal
则是在run
的时候才去copy
调用线程的内容(copy
的时候会返回调用线程的信息),并且会在调用结束后,将调用线程的内容重新塞回去
为什么要再塞回去,我想的是考虑了调用线程池时,策略为java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy#CallerRunsPolicy
时,线程池满了交由调用线程执行时,此时线程执行内容中修改了threadLocals
后对调用线程造成干扰。
使用demo
//只需要包裹一下即可
com.alibaba.ttl.TtlRunnable.get(java.lang.Runnable, boolean)
ttlRunnable.run();
//也可以包裹线程池Executors,其实内部在execute时也还是用的 TtlRunnable.get
ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1));