在同一个线程/同一个请求中,进行数据共享就可以使用 ThreadLocal。

在 Java 开发中,ThreadLocal 是一种用于线程隔离数据存储的机制,常被用来在同一个线程内传递和共享数据。它并不是传统意义上的“数据共享”工具,而是一种线程级别的私有数据存储

简单来说,ThreadLocal 为每个使用它的线程提供一个独立的变量副本。这意味着:

  • 每个线程对 ThreadLocal 变量的读写都发生在自己的副本上;
  • 不同线程之间的 ThreadLocal 变量互不干扰,彼此隔离;
  • 因此,ThreadLocal 不能实现跨线程的数据共享,反而正是为了避免共享而设计的。

正因为这种“线程封闭”的特性,ThreadLocal 在多线程环境下非常有用,尤其是在以下场景中:

  • 避免频繁传递参数(如用户上下文、事务ID、请求追踪ID等);
  • 结合线程池使用时保存线程上下文信息;
  • 在 Spring Boot 应用中,常用于存储请求级别的用户认证信息(如 SecurityContext)或 MDC(Mapped Diagnostic Context)日志追踪。

例如,在 Web 应用中,我们可以在请求开始时将用户信息存入 ThreadLocal,在整个请求处理链路中(如 Controller → Service → DAO)都可以方便地获取该信息,而无需层层传递参数。

但需要注意:

  1. 内存泄漏风险:由于 ThreadLocal 的底层是通过 ThreadLocalMap 存储数据,而 Thread 可能长时间存活(如线程池中的线程),如果不及时调用 remove() 方法清除数据,可能导致内存泄漏。
  2. 线程复用问题:在线程池环境中,线程会被重复使用,若不清理 ThreadLocal 中的数据,可能导致下一个任务错误地读取到上一个任务的残留数据。

接下来展示基本的代码:

public class CurrentHolder {

    private static final ThreadLocal<Integer> CURRENT_LOCAL = new ThreadLocal<>();

    // 将 data 数据存入 ThreadLocal 中
    public static void setCurrentId(String data) {
        CURRENT_LOCAL.set(data);
    }
    
    // 从 ThreadLocal 取出存储的数据
    public static String getCurrentId() {
        return CURRENT_LOCAL.get();
    }
    
    // 删除 ThreadLocal  中存储的值
    public static void remove() {
        CURRENT_LOCAL.remove();
    }
}

外界调用以上方法就可以快速地实现存值、取值、清除功能。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐