
📚博客主页:代码探秘者
✨专栏:文章正在持续更新ing...
✅C语言/C++:C++(详细版) 数据结构) 十大排序算法
✅Java基础:JavaSE基础 面向对象大合集 JavaSE进阶 Java版数据结构JDK新特性
✅后端经典框架: 后端基础 SpringBoot Tlias项目(含SSM)
✅数据库:Mysql
✅常用中间件:redis入门+实战 Elasticsearch RabbitMQ
✅Linux: 部署篇
✅微服务:微服务
❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️
🙏作者水平有限,欢迎各位大佬指点,相互学习进步!

文章目录
- [线程数据共享和安全 -ThreadLocal](#线程数据共享和安全 -ThreadLocal)
-
- [🧠1. 什么是 ThreadLocal?](#🧠1. 什么是 ThreadLocal?)
-
- [🔧 ThreadLocal 常用方法](#🔧 ThreadLocal 常用方法)
- [🎯 典型用途场景(保存用户登录信息(如当前用户 ID))](#🎯 典型用途场景(保存用户登录信息(如当前用户 ID)))
- 2.解析
-
- [🎯 1. 作用:线程内共享变量,解决线程安全问题](#🎯 1. 作用:线程内共享变量,解决线程安全问题)
- [🧷 2. 存值方法:`set()` 给当前线程绑定数据](#🧷 2. 存值方法:
set()
给当前线程绑定数据) - [🔍 3. 获取方法:`get()` 相当于线程私有 Map 的 `get(key)`](#🔍 3. 获取方法:
get()
相当于线程私有 Map 的get(key)
) - [🧩 4. 一个 ThreadLocal 对象 = 一个数据槽位](#🧩 4. 一个 ThreadLocal 对象 = 一个数据槽位)
- [🧱 5. 建议使用 `static` 修饰 ThreadLocal 实例](#🧱 5. 建议使用
static
修饰 ThreadLocal 实例) - [🧹 6. 自动释放内存(前提:线程终结)](#🧹 6. 自动释放内存(前提:线程终结))
- 其他常见注意
- [📦 延伸阅读](#📦 延伸阅读)
线程数据共享和安全 -ThreadLocal
🧠1. 什么是 ThreadLocal?
ThreadLocal
是 Java 提供的线程本地变量工具类,它为每个线程提供了一个独立的变量副本。
- 本质:为每个线程分配独立副本,不共享数据
- 用途:解决多线程中共享变量引起的数据混乱
1.ThreadLocal 的作用,可以实现在同一个线程数据共享, 从而解决多线程数据安全问题.
2.ThreadLocal 可以给当前线程关联一个数据(普通变量、对象、数组)set 方法 [源码!]
3.ThreadLocal 可以像 Map 一样存取数据,key 为当前线程, get 方法
4.每一个 ThreadLocal 对象, 只能为当前线程关联一个数据,如果要为当前线程关联多个数 据,就需要使用多个 ThreadLocal 对象实例
5.每个 ThreadLocal 对象实例定义的时候,一般为 static 类型
6.ThreadLocal 中保存数据,在线程销毁后,会自动释放(建议手动释放) 。
🔧 ThreadLocal 常用方法
方法 | 说明 |
---|---|
set(T value) |
设置当前线程的变量值 |
get() |
获取当前线程的变量值 |
remove() |
移除当前线程的变量值,避免内存泄漏(重要) |
🎯 典型用途场景(保存用户登录信息(如当前用户 ID))
java
public class UserContext {
private static final ThreadLocal<Long> userIdHolder = new ThreadLocal<>();
public static void setUserId(Long id) {
userIdHolder.set(id);
}
public static Long getUserId() {
return userIdHolder.get();
}
public static void clear() {
userIdHolder.remove();
}
}
📍通常配合拦截器、过滤器、JWT 使用:登录验证完后存入 ThreadLocal,业务代码就能直接获取当前用户 ID,无需每层传参。
当然也可以保存用户的一些信息
java
private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();
2.解析
🎯 1. 作用:线程内共享变量,解决线程安全问题
✅ ThreadLocal 可实现线程内的数据共享,从而避免多线程访问共享数据造成冲突。
🧷 2. 存值方法:set()
给当前线程绑定数据
🧪 可绑定 基本类型 / 对象 / 数组 / Map 等 任意数据
java
threadLocal.set("userId-123");
🔍 3. 获取方法:get()
相当于线程私有 Map 的 get(key)
🗂️ 每个线程维护一份 ThreadLocalMap,key 是线程,value 是你 set 的值
java
String value = threadLocal.get();
🧩 4. 一个 ThreadLocal 对象 = 一个数据槽位
📦 想为同一线程绑定多个值?你就要 new 多个
ThreadLocal
实例,例如:
java
public static ThreadLocal<String> userName = new ThreadLocal<>();
public static ThreadLocal<Long> userId = new ThreadLocal<>();
🧱 5. 建议使用 static
修饰 ThreadLocal 实例
🧷 常作为工具类全局使用,方便访问、只初始化一次
java
public static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
🧹 6. 自动释放内存(前提:线程终结)
🛡️ 线程销毁后,ThreadLocal 中数据会被自动 GC 清理
❗ 但如果线程池中复用线程,必须手动调用
remove()
防止内存泄漏
java
threadLocal.remove(); // 非常重要
其他常见注意
✅ 数据库多数据源切换
用 ThreadLocal 存放当前线程使用的数据源标识,在 AOP 或拦截器中切换。
✅ 日志 traceId 链路追踪(如打印统一 traceId)
🧱 ThreadLocal 与并发安全
情况 | 是否线程安全 |
---|---|
普通变量 | ❌ 多线程共享,容易数据混乱 |
ThreadLocal |
✅ 每个线程独立副本,互不影响 |
⚠️ 注意事项(新手必须知道)
🔺 一定要手动 remove()!
- 原因:ThreadLocal 引用的是线程私有变量,线程池复用线程时可能出现 内存泄漏
- 解决:
- 处理完必须调用
ThreadLocal.remove()
- 或使用
try-finally
包裹清除逻辑
- 处理完必须调用
java
try {
ThreadLocalHolder.set(value);
// 业务处理
} finally {
ThreadLocalHolder.remove();
}
📦 延伸阅读
内容 | 推荐方向 |
---|---|
ThreadLocalMap | 底层实现结构(Map) |
InheritableThreadLocal | 子线程继承父线程变量 |
Spring 中的使用 | RequestContextHolder 、SecurityContextHolder |
与线程池结合 | 使用后强制清理,尤其注意 @Async 、CompletableFuture |