ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal的区别
ThreadLocal
在下面的案例中,local.get()取到的值是null,因为子线程获取不到主线程的值。用InheritableThreadLocal可以让子线程获取到主线程的值。
public static void main(String[] args) {
ThreadLocal<String> local = new ThreadLocal<>();
local.set("123");
/**local.get()是null
* 虽然 local 是在主线程中定义的,但它只是一个引用.
* 当你在不同线程中调用 local.get() 或 local.set(...) 时,
* 操作的是当前线程内部的变量副本
*/
Thread thread = new Thread(() -> {
String s = local.get();
System.out.println(s);
});
thread.start();
}
InheritableThreadLocal
在下面的案例中,local.get()就可以获取到主线程的值了。
public static void main(String[] args) {
InheritableThreadLocal<String> local = new InheritableThreadLocal<>();
local.set("123");
/**local.get()是null
* 虽然 local 是在主线程中定义的,但它只是一个引用.
* 当你在不同线程中调用 local.get() 或 local.set(...) 时,
* 操作的是当前线程内部的变量副本
*/
Thread thread = new Thread(() -> {
String s = local.get();
System.out.println(s);
});
thread.start();
}
缺点:
| 缺点 | 说明 |
|---|---|
| 不适用于线程池 | 父子关系不明确,值无法正确传递 |
| 内存泄漏风险 | 没有及时 remove 可能导致泄露 |
| 多级嵌套复杂 | 值层层继承,难以控制 |
| 数据不可同步 | 子线程修改不影响父线程 |
以第四个缺点举例:
public static void main(String[] args) throws InterruptedException {
InheritableThreadLocal<String> local = new InheritableThreadLocal<>();
local.set("123");
/**local.get()是null
* 虽然 local 是在主线程中定义的,但它只是一个引用.
* 当你在不同线程中调用 local.get() 或 local.set(...) 时,
* 操作的是当前线程内部的变量副本
*/
Thread thread = new Thread(() -> {
String s = local.get();
System.out.println("子线程获取值:"+s);
String str = "456";
local.set(str);
System.out.println("子线程设置了新的值:"+str);
});
thread.start();
thread.join();
System.out.println("主线程最后获取值:"+local.get());
}
TransmittableThreadLocal
1、支持线程池传递上下文
2、支持嵌套异步传递
3、兼容性好
使用场景
1、需要在多线程环境下传递用户上下文(如 Trace ID、登录信息等)
2、使用线程池、异步任务(CompletableFuture)、RPC 调用链追踪等场景
3、分布式系统中日志链路追踪(如配合 SkyWalking、Sleuth)

浙公网安备 33010602011771号