Alibaba的TransmittableThreadLocal
TransmittableThreadLocal特性
- 由于基于
InheritableThreadLocal,可以在当前线程直接新建线程的场景,继承ThreadLocal值 - 配合
ExecutorServiceTtlWrapper,可以在使用线程池的场景,继承ThreadLocal值
先看看InheritableThreadLocal的实现
- 线程Thread初始化时有一个
boolean inheritThreadLocals参数,用于是否继承父线程的ThreadLocals值,默认true - 在线程初始化时即完成继承,后续父线程修改也不会影响到当前线程
1 | if (inheritThreadLocals && parent.inheritableThreadLocals != null) |
案例对比
1 | inheritThreadLocals |
new Thread() + InheritableThreadLocal,可取到
1 | InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>(); |
线程池 + InheritableThreadLocal,不可取到
- 原因:线程初始化没有ThreadLocal信息
1 | ExecutorService executor = Executors.newFixedThreadPool(1); |
new Thread() + TransmittableThreadLocal,和InheritableThreadLocal一致
1 | TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>(); |
原生线程池 + TransmittableThreadLocal,不可取到
1 | ExecutorService executor = Executors.newFixedThreadPool(1); |
TTL包装器线程池 + TransmittableThreadLocal,可取到
1 | ExecutorService executor = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1)); |
大致原理
包装器
ExecutorServiceTtlWrapper在submit等相关方法时,将Runnable包装为TtlRunnableTtlRunnable初始化时保存当前线程的所有TransmittableThreadLocal上下文(capture),在执行run方法时,先设置这些上下文(replay),再执行业务代码,最后在finally里恢复执行前的状态(restore)TransmittableThreadLocal在执行set时,会将当前TransmittableThreadLocal添加到线程的holder内,意味着该线程以及该线程在使用线程池时,需要该ThreadLocal
核心方法解释
capture:在第一个线程执行,保存当前线程的holder中,每个TransmittableThreadLocal和值的mapping,提供一个refreplay:在第二个线程执行,通过ref,重新在当前线程设置capture中的值,方法返回设置前holder内的值mapping作为backuprestore:使用backup恢复状态
其他特性
- 线程间传递值时,可自定义copy方式,默认直接传递引用
- 使用
TransmittableThreadLocal.Transmitter.registerThreadLocal(ThreadLocal,TtlCopier)方法,将现有ThreadLocal也能支持该特性