怎么让子线程也能拥有主线程ThreadLocal的值呢,很多童鞋第一反应是重写线程池的线程初始化方法,在初始化的的时候将ThreadLocal中保存的数据copy一份到子线程。这种方法是行不通的。线程池中的线程运行策略是判断当前队列中是否有任务,如果没有任务,则会在设定的时间后销毁;如果有任务,则会继续领下一个任务继续执行,而一般拒绝策略是CallerRunsPolicy。
为了解决线程池中变量传递,可以使用TransmittableThreadLocal的类,继承于InheritableThreadLocal。它通过包装返回Runnable的方式代理了run方法,在run之前copy装载线程变量,run之后清除线程变量,来实现此功能。为此需要修改runable接口。
com.alibaba.ttl.TtlRunnable#run 这个才是真正执行的run方法
Object backup = replay(captured);
try {
runnable.run();
} finally {
restore(backup);
}
TransmittableThreadLocal除了继承过来的线程Map,它还定义了一个名叫holder的InheritableThreadLocal静态变量,也就是说TransmittableThreadLocal有两套线程变量。
使用方法:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.5.0</version>
</dependency>
先调用TransmittableThreadLocal.set保存线程变量,除了正常保存外,还会保存到holder里。其实这么设置一下,当前线程的Map里就有两个Key-Value了,一个是TransmittableThreadLocal本身的,一个是holder的,并且holder真实的Value是一个WeakHashMap(也是弱引用),而且这个WeakHashMap会把TransmittableThreadLocal引用本身当做Key保存起来。外面传过进来的变量设置到当前执行任务的线程上去。run之后调用restoreBackup清除当前线程上被copied设置的变量并还原backup。