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

ThreadLocal 详解

1. 是什么

ThreadLocal 是线程本地变量,给每个线程提供独立的变量副本,互不影响。

2. 简单用法

publicclassUserContext{privatestaticfinalThreadLocal<String>USER=newThreadLocal<>();publicstaticvoidset(Stringuser){USER.set(user);}publicstaticStringget(){returnUSER.get();}publicstaticvoidremove(){USER.remove();}}// 使用UserContext.set("张三");Stringuser=UserContext.get();// 同一个线程里拿到的都是"张三"UserContext.remove();

3. 常见场景

用户信息传递

不用每次方法参数传递:

// 登录时存进去UserContext.set(SecurityContext.getUser());// 任何地方都能取到publicvoidanyMethod(){Useruser=UserContext.get();// 拿到当前登录用户}

数据库连接

保证同一线程用的是同一个连接:

privatestaticfinalThreadLocal<Connection>DB=newThreadLocal<>();// 获取连接publicConnectiongetConnection(){Connectionconn=DB.get();if(conn==null){conn=dataSource.getConnection();DB.set(conn);}returnconn;}

请求Tracer

privatestaticfinalThreadLocal<String>TRACE_ID=newThreadLocal<>();publicvoidhandleRequest(){TRACE_ID.set(UUID.randomUUID().toString());log.info("开始处理, traceId={}",TRACE_ID.get());// 整个调用链都能拿到同一个 traceId}

4. 原理

每个 Thread 对象里有个 ThreadLocalMap:

Thread └── threadLocals: ThreadLocalMap ├── ThreadLocal<?> → value ├── ThreadLocal<?> → value └── ...

set 时,把 ThreadLocal 对象作为 key,存到当前线程的 Map 里。

get 时,从当前线程的 Map 里,用 ThreadLocal 对象作为 key 取值。

所以不同线程访问同一个 ThreadLocal,拿到的值不一样。

5. 内存泄漏

ThreadLocalMap 的 Entry 继承 WeakReference:

staticclassEntryextendsWeakReference<ThreadLocal<?>>{Objectvalue;Entry(ThreadLocal<?>k,Objectv){super(k);value=v;}}

key(ThreadLocal 对象)是弱引用,理论上会被 GC 回收。但 value 是强引用,可能造成泄漏。

所以用完要 remove!

try{Useruser=UserContext.get();}finally{UserContext.remove();// 用完清理}

6. 总结

  • 每个线程独立副本,互不干扰
  • 常用场景:用户信息传递、数据库连接、链路追踪
  • 用完记得 remove,防止内存泄漏
http://www.jsqmd.com/news/542889/

相关文章:

  • 从ORA-600到闪回技术:Oracle错误代码背后的架构设计启示录
  • 浦语灵笔2.5-7B可部署特性:支持国产化环境适配与信创平台迁移
  • 经纬度计算避坑指南:为什么你的Haversine公式结果不准确?
  • 7_Harness驾驭工程安全与成本层:DevSecOps与云成本优化
  • VRM-Addon-for-Blender:虚拟角色创作全流程指南
  • 什么是 Cookie?什么是 Session?它们的作用分别是什么?
  • 基于stm32的智能书房系统[单片机]-计算机毕业设计源码+LW文档
  • 手把手教你用SonarQube+Burp Suite完成等保三级代码安全自查(附避坑指南)
  • 水墨江南模型Ubuntu系统部署教程:从零开始的环境配置
  • 开源AI工作站实测:Pixel Fashion Atelier在Jetson AGX Orin边缘端部署
  • OpenClaw定时任务管理:ollama-QwQ-32B实现智能提醒系统
  • Qwen3-0.6B-FP8代理能力展示:调用计算器、查天气、解析PDF的Chainlit实录
  • UE5 Widget Blueprint实战:5分钟搞定动态血量条与得分系统(附完整蓝图代码)
  • 【调试心法】别用 printf 谋杀你的系统了!打破“测不准”魔咒,用 C++ 与 DMA 构筑微秒级零开销异步观测者
  • 2026靠谱的防潮箱厂家推荐及核心业务解析 - 品牌排行榜
  • 虚拟化技术概览
  • 从连续到离散:二阶巴特沃斯低通滤波器的工程实现与参数设计
  • StarUML新手必看:5分钟搞定ER图绘制(附详细步骤截图)
  • MedGemma 1.5开源可部署:MIT许可下可二次开发、商用、集成进医疗SaaS系统
  • 8_Harness驾驭工程实践:企业级落地与OpenAI案例解析
  • 华为光猫配置解密工具技术架构解析与实现机制
  • 如何通过SketchUp STL插件实现高效3D打印工作流:7个关键技术要点解析
  • 解锁浏览器无限可能:Greasy Fork用户脚本平台全解析
  • 第4章 编码规范-4.1 命名规范
  • PX4飞控系统深度解析:从模块化架构到自主飞行核心技术揭秘
  • PVE 8.3.0保姆级教程:搞定EVE-NG社区版6.2.0-4与Windows虚拟机共存
  • Qwen3.5-4B-Claude-Opus实际作品:正则表达式语法树构建与匹配逻辑推演
  • 05计算属性与定时器
  • Windows下OpenClaw安装指南:对接ollama GLM-4.7-Flash模型
  • 告别‘无法启动’!VS2019+QT项目打包保姆级教程(含VTK等第三方库处理)