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

threadlocal的实现说明

目录

1.说明

2.弱引用的说明

3.最佳实践

4.方法说明


1.说明

在每个Thread中包含一个threadlocalmap对象,ThreadLocalMap是TheadLocal的静态内部类

threadLocalMap内部是一个entry数组
每个entry的key是TheadLoca实例,key是一个弱引用
每个entry的value是设置的内容,是强引用

如果在方法中new 一个threadlocal实例时,内存占用如下:

+------------------+     +-------------------+     +-----------------------+
|  方法栈帧         |     |  堆内存           |     |  线程的 ThreadLocalMap |
|                  |     |                   |     |                       |
| threadLocal 引用 ──────> ThreadLocal实例    |     | +-------------------+ |
+------------------+     +-------------------+     | | Entry:            | || | Key:  弱引用ThreadLocal || | Value:强引用"value"  | || +-------------------+ |+-----------------------+

当方法结束后,方法栈帧弹出,这时ThreadLocal对象的引用消失,ThreadLocalMap中的Key(ThreadLocal对象)是弱引用(WeakReference)。

当外部对ThreadLocal的强引用消失后,GC回收时发现无强引用指定,

仅有 Entry 的弱引用指向
→ 立即回收 Key 对象,并将 Entry 的 Key 置为 null(弱引用自动被清除)。
虽然 Key 被回收,但 Entry 中的 value 仍是强引用,此时会形成:
Entry { key=null, value="SomeValue" } // Value 无法被访问,存在内存泄漏风险

2.弱引用的说明

弱引用特性:当 JVM 进行垃圾回收时,如果 Key 仅被弱引用指向(没有强引用),无论内存是否充足,都会回收该 Key 对象。 

为什么设计为弱引用?

主要目的:防止开发者忘记调用 remove() 时,ThreadLocal 对象本身无法被回收。

    如果 Key 是强引用:即使开发者不再使用 ThreadLocal,由于线程的 ThreadLocalMap 持有强引用,ThreadLocal 对象和 Value 会永远无法回收。

    弱引用设计是一种兜底机制,至少能回收 Key,但需配合 remove() 彻底清理。

3.最佳实践

①使用static + final 定义threadlocal实例

// 推荐:static + final 修饰
private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();

static 确保全局唯一实例,避免重复创建,不是对象属性,而是类的属性,一直持有引用,除非类被卸载,final 防止意外修改引用

②使用完成后执行remove处理

try {
CONTEXT_HOLDER.set(value);
} finally {
CONTEXT_HOLDER.remove(); // 必须清理
}

remove处理会清楚key和value,确保可以被回收

4.方法说明

get方法:

    public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();}
  1. 获取当前线程
  2. 根据线程获取线程的threadlocalmap变量
  3. 如果为空,代表首次赋值,会创建一个threadlocalmap实例,key设置为threadlocal实例,并将值保存为null
  4. 如果不为空,则根据threadlocal实例获取对应的内容

set方法:

    public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);}
  1. 获取当前线程
  2. 获取线程的threadlocalmap变量
  3. 如果不为空,key设置为threadlocal实例,并将值保存为参数中传递的内容
  4. 如果为空,会创建一个threadlocalmap实例,key设置为threadlocal实例,并将值保存为参数中传递的内容

remove方法:

    public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);}

 会清除key及value,并且无效Entry被清理

http://www.xdnf.cn/news/972109.html

相关文章:

  • python46
  • 端到端自动驾驶研究:通过强化学习与世界模型的协同作用向VLA范式演进
  • 曼昆《经济学原理》第九版 第十三章生产成本
  • 智能呼入系统助力酒店客服服务
  • 使用mpu6500/6050, PID,互补滤波实现一个简单的飞行自稳控制系统
  • 2025.6.10【ZR NOI模拟赛 T3】 过啥题 题解(Lucas 定理, 数位dp, 组合意义)
  • Java设计模式基础问答
  • 通过Wrangler CLI在worker中创建数据库和表
  • QFuture的使用方式
  • vue的created和mounted区别
  • 替代爬虫!亚马逊API采集商品详情实时数据开发教程
  • 《Java开发者进击之路:掌握Spring AI与DL4J,实现AI模型API集成》
  • MCU Keil中支持的变量类型和定义方法
  • 美业门店/个案疗愈门店管理系统具备「活动促销」功能有哪些优势?
  • 多面体编译的循环分块
  • iOS和桌面双端抓包实战经验总结:Sniffmaster与常见工具组合解析
  • 算法工程师工作面试常考问题汇总
  • HarmonyOS 应用开发学习记录 - 从Windows开发者视角看鸿蒙开发
  • RabbitMQ的使用--Spring AMQP(更新中)
  • 期末考试复习总结-《从简单的页面开始(上)》
  • CentOS7下的Nginx部署
  • 行业 |5G六年,互联网改变了什么?
  • WHAT - 组件库开发场景 - 完全无样式的 UI 组件库 Headless UI
  • 看板更新不及时该如何规范
  • jQuery带动画特效的圆形导航菜单特效
  • Playwright 与 Selenium:自动化测试的两大主流工具对比
  • iOS超级签申请流程及环境部署
  • 从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
  • 二叉树进阶:经典算法题详解
  • AD8539ARZ ADI 精密放大器 电子元器件解析