当前位置: 首页 > 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被清理

相关文章:

  • Doris “_stream_load“ 方式批量导入数据
  • 使用Ajax从前端向后端发起请求
  • 算法第12天|继续学习二叉树:翻转二叉树、对称二叉树、二叉树最大深度、二叉树的最小深度
  • 铭豹扩展坞 USB转网口 突然无法识别解决方法
  • 蓝奏云(Lanzou Cloud)一款国内知名的免费网盘和文件分享服务 以及蓝奏云的api
  • APM32芯得 EP.10 | 基于APM32F411控制的一个软开关电路设计分享
  • Word-- 制作论文三线表
  • Python 字符串、字节串与编解码:数据转换的奥秘
  • 【Python】 -- 趣味代码 - 扫雷游戏
  • Jaeger开源分布式追踪平台深度剖析(三)Jaeger默认存储Badger原理剖析
  • Docker安装openGauss
  • pont拉取代码
  • git管理github上的repository(二)
  • 2025 Java 面试大全
  • A 找倍数 (线段树)
  • 嵌入式学习笔记DAY35(数据库)
  • 龙虎榜——20250610
  • 算法题(166):占卜DIY
  • Zustand 状态管理库:极简而强大的解决方案
  • 城市照明深夜全亮太浪费?智能分时调光方案落地贵州某市
  • 网站开发 注意事项/友情链接属于免费推广吗
  • 徐州手机网站优化公司/西安网络推广优化培训
  • 多语言网站是怎么做的/指数基金定投技巧
  • 电商网站如何做引流/给我免费播放片高清在线观看
  • 南山做网站多少钱/推广网站推广
  • android移动网站开发详解/国家卫生健康委