ThreadLocal讲解

62 阅读2分钟

ThreadLocal 是 Java 中一个非常重要但容易被误解的工具,尤其是在 多线程开发 中。它和普通变量、线程共享变量有本质区别,适用于一些每个线程都需要独立数据副本的场景

✅ 一、什么是 ThreadLocal?

ThreadLocal 代表线程局部变量:每个线程有自己独立的副本变量互不干扰

简单说: “变量是你自己的,别人线程拿不到”

📦 二、ThreadLocal 的原理结构

每个线程(Thread)内部都有一个 ThreadLocalMap,用于存储所有该线程自己的 ThreadLocal 变量。

ThreadLocal<String> local = new ThreadLocal<>();
local.set("小杰");  // 只对当前线程可见

背后大致等价于:

threadLocalMap.put(currentThread, "小杰");

所以:

  • 每个线程都有一份自己的变量副本;
  • 不同线程对同一个 ThreadLocal 实例,存的是自己线程内部的一份值

🧪 三、使用示例

示例1:基本用法

public class ThreadLocalExample {
    private static final ThreadLocal<String> userHolder = new ThreadLocal<>();

    public static void main(String[] args) {
        Runnable task = () -> {
            userHolder.set(Thread.currentThread().getName());
            System.out.println("线程:" + Thread.currentThread().getName() + " 的用户是:" + userHolder.get());
        };

        new Thread(task, "线程A").start();
        new Thread(task, "线程B").start();
    }
}

📌 输出结果中每个线程都能拿到自己的值,不冲突。

示例2:配合数据库连接、登录用户、事务等

public class UserContext {
    private static final ThreadLocal<String> currentUser = new ThreadLocal<>();

    public static void setUser(String username) {
        currentUser.set(username);
    }

    public static String getUser() {
        return currentUser.get();
    }

    public static void clear() {
        currentUser.remove(); // ✅ 必须手动清除,防止内存泄露
    }
}

用法:

UserContext.setUser("小杰");
System.out.println("当前用户:" + UserContext.getUser());
UserContext.clear();

🚨 四、注意事项(重要)

⚠️ 问题描述
内存泄漏风险如果是在线程池中使用 ThreadLocal线程不会销毁,不手动 .remove() 会导致对象一直存在内存中
生命周期长一定记得在使用完后调用 .remove()
线程隔离,不共享如果你想在线程之间共享变量,不适用 ThreadLocal,应用共享变量、锁等

📌 五、典型应用场景

场景说明
登录用户信息每个请求线程记录当前登录用户
日志链路追踪每个请求线程绑定唯一 traceId
数据源切换多数据源情况下记录当前线程使用哪个 DB
数据库连接管理每个线程持有独立连接(如 Spring JDBC)

✅ 总结一句话 ThreadLocal 是实现 线程内数据隔离 的工具,适合在高并发环境下存储用户上下文、连接等数据,但必须及时清除,否则容易内存泄漏。