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

为什么 ThreadLocalMap 的 key 是弱引用 value是强引用

问题一:为什么 ThreadLocalMap 的 key 是弱引用?

【假设 Entry 的 key 是对 ThreadLocal 对象的强引用】:这个 Entry 又持有 ThreadLocal 对象和 value 对象的强引用。如果在其他地方都没有对这个 ThreadLocla 对象的引用了、然后在使用 ThreadLocalMap 的过程中又没有正确地在用完后就调用 remove 方法、所以这个 ThreadLocal 对象和所关联的 value 对象就会跟随着线程一直存在、这样就会可能会造成内存泄漏问题。

特别是在使用线程池的时候、核心线程是会一直存在直到程序结束、如果这些线程中的 ThreadLocalMap 中的数据没有被及时清理、就会一直占用内存、而且在线程复用时可能会导致数据错乱的危险。

【Entry 的 key 是对 ThreadLocal 对象的弱引用】:弱引用就意味着、如果没有其他引用对象的强引用关系、那么这个仅被弱引用引用着的对象在下次 GC 时就会被回收掉、这样在一定程度上降低内存泄漏的风险。但同时也引入了新的问题、key 虽然被回收了、但是 value 对象还在、我们无法获取、也无法删除、这样也会存在内存泄漏的风险。

虽然 ThreadLocalMap 中在进行 set 和 get 操作时会进行启发式清理和探测式清理、清理一部分 key 为 null 的 Entry 对象、但是这也只是一种后备选择方案

最重要的还是开发人员在编写代码时记得在使用完数据后及时调用 remove() 方法手动清理

补充:

【内存泄漏就是:有些对象已经不再使用了、但是由于没有正确处理对象的引用关系、使得这个无用的对象还一直被 GC Root 直接或间接引用着、垃圾回收时就无法清理掉这些对象、如果这类对象存在很多、就会导致内存泄漏。简单地说就是有些无用对象占用着宝贵的内存空间、但又没办法清理掉它们 可达性分析是现代垃圾回收器用来判断对象是否存活的核心算法】

问题二:为什么 ThreadLocalMap 的 value 是强引用?

【假设Entry 的 value 是弱引用】:假设 key 所引用的 ThreadLocal 对象还被其他的引用对象强引用着,那么这个 ThreadLocal 对象就不会被 GC 回收、但如果 value 是弱引用且不被其他引用对象引用着、那 GC 的时候就被回收掉了、那线程通过 ThreadLocal 来获取 value 的时候就会获得 null,显然这不是我们希望的结果。因为对我们来说、value 才是我们想要保存的数据、ThreadLcoal 只是用来关联 value 的、如果 value 都没了、还要 ThreadLocal 干啥呢

面试参考回答:

面试官您好关于 ThreadLocalMap 的 key 使用弱引用、value 使用强引用的问题

我的理解是这样的:

首先要理解这样设计的目的是为了尽可能地避免内存泄漏。

  • Key 使用弱引用 假设 key 是强引用、那么即使 ThreadLocal 对象本身已经没有其他地方引用了、由于 ThreadLocalMap 中 Entry 的强引用、这个 ThreadLocal 对象仍然无法被垃圾回收。如果线程一直存活(比如线程池中的线程)、这个 ThreadLocal 对象和对应的 value 就会一直占用内存、造成内存泄漏。使用弱引用、当 ThreadLocal 对象没有外部强引用时、在下次 GC 的时候、key 就会被回收、降低了内存泄漏的风险。

  • Value 使用强引用: Value 是我们真正想要存储的数据,如果 value 也使用弱引用、那么在 ThreadLocal 对象还存活的情况下、value 却可能因为没有强引用而被 GC 回收、导致我们通过 ThreadLocal 获取到的 value 为空、这显然是不符合 ThreadLocal 的设计目的的。ThreadLocal 的作用就是关联数据、如果数据都没了ThreadLocal 就失去了意义。

而且虽然 key 使用弱引用可以降低内存泄漏的风险、但仍然存在 value 无法回收的问题。

当 key 被回收后value 仍然被 Entry 强引用。如果线程一直存活、这个 value 就会一直占用内存。

因此ThreadLocalMap 在 set()get() 操作时会进行启发式清理、移除 key 为 null 的 Entry 但这只是一个补救措施。

最根本的解决办法还是需要开发者在使用完 ThreadLocal 后、手动调用 remove() 方法、及时清理 ThreadLocalMap 中的 Entry,避免内存泄漏。

总结: 弱引用 key 降低了 ThreadLocal 对象本身的内存泄漏风险、强引用 value 保证了数据的可用性。

但最终避免内存泄漏、需要开发者养成良好的习惯、及时清理 ThreadLocal。

http://www.dtcms.com/a/101200.html

相关文章:

  • 过滤器filter,监听器Listener
  • Java日志进化论:从System.out.println到日志框架的全面升级
  • 青少年编程与数学 02-013 初中数学知识点 02课题、概要
  • 习题2.1
  • 【免费】2007-2019年各省地方财政医疗卫生支出数据
  • J2EE框架技术 第三章 SSM项目的CURD
  • Netty源码—10.Netty工具之时间轮一
  • BAR帧处理
  • 怎样提升大语言模型(LLM)回答准确率
  • MySQL内存使用率高问题排查与解决方案:
  • Windows10上部署DeepSeek+RAG知识库操作详解(Dify方式)之1
  • GAMES101-现代计算机图形学入门(Assignment7)
  • sql优化子查询展开执行计划测试
  • 【Deepseek】企业AI DeepSeek战略课
  • 生产者消费者模型
  • 金融级密码管理器——密码泄露监控与自动熔断
  • leetcode -编辑距离
  • opencv图像处理之指纹验证
  • Python助力无人机智能路径规划:从理论到实践
  • uniapp选择文件使用formData格式提交数据
  • Vue3 表单
  • STM32 CAN控制器硬件资源与用法
  • 网络编程和Socket套接字(UDP+TCP)(如果想知道Java中有关网络编程和Socket套接字的知识,那么只看这一篇就足够了!)
  • 51单片机的五类指令(二)——算术运算类指令
  • Python库与Excel
  • BUUCTF-web刷题篇(5)
  • Sentinel实战(一)、1、sentinel介绍、安装及初始化服务监控
  • 微信小程序:数据拼接方法
  • MP3、WAV、RM、PNG格式
  • deepseek ai 输入法