TransmittableThreadLocal
是InheritableThreadLocal
的增强版。
- 主要用于解决在线程池环境中父子线程间传递上下文数据的问题。
它由阿里巴巴的开源库
transmittable-thread-local
(TTL
) 提供。
- 解决了
InheritableThreadLocal
在线程池复用线程时数据无法自动传递的问题。
InheritableThreadLocal
可以在父线程和直接创建的子线程间传递数据。但在线程池场景中,由于线程是被复用的,
InheritableThreadLocal
无法正确地将父线程的上下文传递给子线程。
TransmittableThreadLocal
通过增强线程池的执行机制。
- 能够在任务提交时捕获父线程的上下文,并在任务执行时将该上下文传递给子线程,确保上下文的正确传递。
使用示例
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.4</version> <!-- 请使用最新版本 -->
</dependency>
假设我们有一个需要传递上下文信息的场景,在主线程中设置一个值,并希望在线程池中执行任务时能够获取到该值:
public class TransmittableThreadLocalExample {
// 创建 TransmittableThreadLocal 变量
private static final TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>();
public static void main(String[] args) {
// 设置主线程的上下文值
transmittableThreadLocal.set("Parent Thread Value");
// 创建一个线程池,并包装为 TTL 线程池
ExecutorService executorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(2));
// 提交任务
executorService.submit(() -> {
// 子线程中获取 TransmittableThreadLocal 的值
System.out.println("Task 1: " + transmittableThreadLocal.get()); // 输出: Task 1: Parent Thread Value
});
// 修改父线程中的值,提交另一个任务
transmittableThreadLocal.set("Updated Parent Thread Value");
executorService.submit(() -> {
// 子线程获取更新后的值
System.out.println("Task 2: " + transmittableThreadLocal.get()); // 输出: Task 2: Updated Parent Thread Value
});
// 关闭线程池
executorService.shutdown();
}
}
Task 1: Parent Thread Value
Task 2: Updated Parent Thread Value
在这个例子中,
TransmittableThreadLocal
能够将父线程的上下文信息传递到线程池中复用的子线程中。
- 实现了线程池环境下的上下文传递。
工作机制
捕获上下文:
- 在提交任务时,
TransmittableThreadLocal
捕获父线程的上下文数据,并将其附加到任务中。传递上下文:
- 在线程池中执行任务时,
TransmittableThreadLocal
将捕获的上下文设置到当前线程,以便子线程能够访问。清理上下文:
- 任务执行完毕后,
TransmittableThreadLocal
会清理线程中的上下文,避免对后续任务产生影响。
使用场景
TransmittableThreadLocal
常用于以下场景:
分布式追踪:
- 传递追踪 ID、事务 ID 等上下文信息。
日志上下文传递:
- 在不同的子线程中传递用户会话信息、请求 ID,用于生成有上下文的日志。
线程池异步任务:
- 在多线程异步任务中传递父线程的上下文参数(如用户信息、地域信息等)。
注意事项
依赖 TTL 线程池包装:
- 在线程池中使用
TransmittableThreadLocal
时。- 需要将线程池通过
TtlExecutors.getTtlExecutorService
进行包装,否则上下文传递将无法生效。性能开销:
- 由于上下文的捕获、传递和清理机制。
TransmittableThreadLocal
相比普通的ThreadLocal
和InheritableThreadLocal
会有一定的性能开销。