为什么 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。

相关推荐
简简单单做算法4 分钟前
基于mediapipe深度学习和限定半径最近邻分类树算法的人体摔倒检测系统python源码
人工智能·python·深度学习·算法·分类·mediapipe·限定半径最近邻分类树
Tisfy1 小时前
LeetCode 2360.图中的最长环:一步一打卡(不撞南墙不回头) - 通过故事讲道理
算法·leetcode··题解
Aphelios3801 小时前
Java全栈面试宝典:线程机制与Spring IOC容器深度解析
java·开发语言·jvm·学习·rbac
LuckyAnJo1 小时前
Leetcode-100 链表常见操作
算法·leetcode·链表
qq_529835352 小时前
装饰器模式:如何用Java打扮一个对象?
java·开发语言·装饰器模式
日暮南城故里2 小时前
Java学习------源码解析之StringBuilder
java·开发语言·学习·源码
双叶8363 小时前
(C语言)虚数运算(结构体教程)(指针解法)(C语言教程)
c语言·开发语言·数据结构·c++·算法·microsoft
工一木子3 小时前
大厂算法面试 7 天冲刺:第5天- 递归与动态规划深度解析 - 高频面试算法 & Java 实战
算法·面试·动态规划
一个public的class4 小时前
什么是 Java 泛型
java·开发语言·后端
士别三日&&当刮目相看4 小时前
JAVA学习*Object类
java·开发语言·学习