编辑
2025-07-17
学习记录
00

目录

简介
用法
基础用法
链路追踪场景(Trace ID 传递)
注意

简介

InheritableThreadLocal 是 Java 中 ThreadLocal 的子类,用于解决 父子线程间值传递 的问题。与 ThreadLocal 不同,它允许子线程自动继承父线程的变量副本,特别适用于需要跨线程传递上下文信息的场景。

核心特性

  • 继承机制:子线程创建时会自动复制父线程的 InheritableThreadLocal 值。

  • 线程隔离:子线程修改值不会影响父线程(深拷贝副本)。

  • 类型安全:泛型支持(如 InheritableThreadLocal)。

使用场景

  • 传递用户身份信息(如 Session ID)

  • 分布式链路追踪(如 Trace ID)

  • 事务上下文传递

  • 多线程日志标记

  • 跨线程资源管理

用法

基础用法

java
public class InheritableThreadLocalDemo { private static final InheritableThreadLocal<String> context = new InheritableThreadLocal<>(); public static void main(String[] args) { context.set("父线程的值-123"); new Thread(() -> { System.out.println("子线程读取: " + context.get()); // 输出父线程设置的值 context.set("子线程修改的值-456"); // 修改只影响当前线程 }).start(); System.out.println("父线程读取: " + context.get()); // 仍为"父线程的值-123" } }

链路追踪场景(Trace ID 传递)

java
public class TraceContext { private static final InheritableThreadLocal<String> traceId = new InheritableThreadLocal<>(); // 设置当前请求的Trace ID public static void startTrace(String id) { traceId.set(id); } // 获取Trace ID(自动传递到子线程) public static String getTraceId() { return traceId.get(); } // 清理资源 public static void endTrace() { traceId.remove(); } } // 使用示例 public class ServiceA { void processRequest() { TraceContext.startTrace("TRACE-" + UUID.randomUUID()); System.out.println("ServiceA Trace: " + TraceContext.getTraceId()); // 异步处理(子线程继承Trace ID) new Thread(() -> { System.out.println("子服务 Trace: " + TraceContext.getTraceId()); // 输出相同Trace ID }).start(); } }

注意

  • 线程池问题

    线程复用会导致旧值残留,需在任务执行前显式传递值(如上述重写 ThreadFactory)。

  • 内存泄漏风险

    始终在 finally 块中调用 remove() 清理资源:

java
try { context.set(value); // ...业务逻辑 } finally { context.remove(); // 必须清理 }
  • 对象引用

    传递可变对象时,父子线程可能共享同一对象引用(需深拷贝或防御性复制)。

  • 性能影响

    频繁创建线程时,复制操作会有额外开销。

TransmittableThreadLocal(阿里开源) 专为线程池设计,通过 TtlRunnable 包装解决复用问题。

本文作者:Weee

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!