当前位置: 首页 > news >正文

ThreadLocal使用及其原理和注意点

关键注意事项

1.必须调用 remove () 方法
线程池中的线程是复用的,如果不清除,下次复用线程时会读到旧数据,导致逻辑错误或内存泄漏。

2.避免使用 static 滥用
虽然 ThreadLocal 常声明为 static,但需明确其作用域,避免存储过大对象。

3.为什么要使用 static 修饰

如果 ThreadLocal 是非静态的(实例变量),那么每个类实例都会创建一个独立的ThreadLocal 对象。这会导致:

同一个线程中,通过不同的类实例访问 ThreadLocal 时,拿到的是不同容器中的数据(不符合 "线程内全局共享" 的预期)。

例如:UserContext 类的两个实例 ctx1ctx2,它们的非静态 ThreadLocal 会让线程 A 在 ctx1 存的数据,在 ctx2 中读不到。

4.父子线程数据不共享
子线程无法读取父线程的 ThreadLocal 数据,如需共享可使用 InheritableThreadLocal

注意:可以创建多份 ThreadLocal

一个线程中可能同时需要存储:

  • 用户登录信息(User 类型)
  • 数据库事务 ID(String 类型)
  • 本次请求的日志追踪 ID(Long 类型)

此时需要定义多个 ThreadLocal

public class ThreadContext {// 存储用户信息private static ThreadLocal<User> userLocal = new ThreadLocal<>();// 存储事务IDprivate static ThreadLocal<String> transactionIdLocal = new ThreadLocal<>();// 存储日志追踪IDprivate static ThreadLocal<Long> traceIdLocal = new ThreadLocal<>();// 用户信息的get/set/removepublic static void setUser(User user) {userLocal.set(user);}public static User getUser() {return userLocal.get();}public static void removeUser() {userLocal.remove();}// 事务ID的get/set/removepublic static void setTransactionId(String id) {transactionIdLocal.set(id);}public static String getTransactionId() {return transactionIdLocal.get();}public static void removeTransactionId() {transactionIdLocal.remove();}// 日志追踪ID的get/set/removepublic static Long getTraceId() {return traceIdLocal.get();}public static void setTraceId(Long id) {traceIdLocal.set(id);}public static void removeTraceId() {traceIdLocal.remove();}
}

使用上:

// 存储数据
ThreadContext.setUser(new User("张三"));
ThreadContext.setTransactionId("tx-123456");
ThreadContext.setTraceId(10086L);// 读取数据(同一线程内)
User user = ThreadContext.getUser(); // 张三
String txId = ThreadContext.getTransactionId(); // tx-123456

总结

  1. 静态声明 ThreadLocal:是为了保证容器实例唯一,避免资源浪费,确保线程内变量的全局一致性(最常见的使用方式)。
  2. 多个 ThreadLocal 实例:完全合理且必要,用于隔离同一线程中的不同类型变量(如用户信息、事务 ID 等)。

核心原则:一个 ThreadLocal 实例对应一种类型的线程变量,静态声明是为了让这种对应关系全局唯一。

 

 

http://www.lryc.cn/news/599727.html

相关文章:

  • 虚拟机docker elasticsearch启动失败
  • 07 51单片机之定时器
  • react+threejs实现自适应分屏查看/3D场景对比功能/双场景对比查看器
  • 二分查找----6.寻找两个正序数组的中位数
  • 基于深度学习的图像分类:使用Vision Transformer(ViT)实现高效分类
  • Lakehouse x AI ,打造智能 BI 新体验
  • 认识一下Qlib的158因子特征
  • Gitee Test:国产软件测试平台如何筑牢关键领域数字安全屏障
  • PI 思维升级 PI设计的典范转移:从阻抗思维到谐振控制
  • 主要分布在背侧海马体(dHPC)CA1区域(dCA1)的时空联合细胞对NLP中的深层语义分析的积极影响和启示
  • 杂谈:前端开发中的常见问题
  • 【机器学习之推荐算法】基于矩阵分解和损失函数梯度下降的协同过滤算法实现
  • 验证 GitHub Pages 的自定义域(Windows)
  • Power Compiler:漏电功耗、内部功耗、切换功耗及其计算方式(NLPM)
  • 【通识】如何看电路图
  • ATH12K 驱动框架分析
  • Docker容器技术:从入门到精通
  • J2EE模式---数据访问对象模式
  • 电科金仓新一代数据库一体机:以 “云数据库 - AI 版” 引领 AI 时代数据库变革
  • C++中的反向迭代器
  • Linux下使用VSCode配置GCC环境与调试指南
  • 基于单片机的楼宇门禁系统的设计与实现
  • 电商数据采集API与爬虫技术结合的全网比价方案
  • 目前市面上arm64-v8a、armeabi-v7a设备的市占率有多少?为什么x86架构的手机越来越少?
  • Python 数据分析(一):NumPy 基础知识
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-26,(知识点:硬件电路的调试方法:信号追踪,替换,分段调试)
  • 支付宝小程序 DAU 提升策略:激发每日用户活力
  • 破局与重构:King’s LIMS 引领电子行业实验室智能化转型
  • Logstash 多表增量同步 MySQL 到 Elasticsearch:支持逻辑删除与热加载,Docker 快速部署实战
  • Qt 状态机框架:复杂交互逻辑的处理