ThreadLocal
的需求场景即TransmittableThreadLocal
的潜在需求场景,如果你的业务需要『在使用线程池等会池化复用线程的执行组件情况下传递ThreadLocal
值』则是TransmittableThreadLocal
目标场景。
下面是几个典型场景例子。
Session
级Cache
SDK
传递信息使用类TransmittableThreadLocal
来保存值,并跨线程池传递。
TransmittableThreadLocal
继承InheritableThreadLocal
,使用方式也类似。相比InheritableThreadLocal
,添加了
copy
方法ThreadLocal
值传递到 任务执行时 的拷贝行为,缺省传递的是引用。InheritableThreadLocal.childValue
一样,使用者/业务逻辑要注意传递对象的线程安全。protected
的beforeExecute
/afterExecute
方法Runnable
/Callable
)的前/后的生命周期回调,缺省是空操作父线程给子线程传递值。
public static void main(String[] args) throws InterruptedException {
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// 在父线程中设置值
context.set("value-set-in-parent");
System.out.println("父线程中的数据:" + context.get());
new Thread(()->{
// 在子线程中获取父线程中的数据
String value = context.get();
System.out.println("子线程获取父线程中的数据:" + value);
}).start();
Thread.sleep(10000);
}
父线程中的数据:value-set-in-parent
子线程获取父线程中的数据:value-set-in-parent
这种普通的异步子线程能正常获取父线程中的数据。
2. 保证线程池中传递值
private static ExecutorService executorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(2));
//这里采用TTL的实现
private static ThreadLocal tl = new TransmittableThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
String mainThreadName = "main_01";
tl.set(1);
executorService.execute(() -> {
sleep(2L);
System.out.println(String.format("本地变量改变之前(1), 父线程名称-%s, 子线程名称-%s, 变量值=%s", mainThreadName, Thread.currentThread().getName(), tl.get()));
});
tl.set(2);
executorService.execute(() -> {
sleep(1L);
System.out.println(String.format("本地变量改变之后(2), 父线程名称-%s, 子线程名称-%s, 变量值=%s", mainThreadName, Thread.currentThread().getName(), tl.get()));
});
}).start();
}
private static void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
当前版本的Java API文档地址: https://alibaba.github.io/transmittable-thread-local/apidocs/
示例:
<dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> <version>2.12.1</version> </dependency>