1. 什么是 Reference
?
Reference
是 Java 中处理引用类型的基类(在 java.lang.ref
包中)。它有四个直接子类,代表四种引用强度:
强引用 (Strong Reference):普通的对象引用(
Object obj = new Object()
),只要存在强引用,对象就不会被 GC 回收软引用 (SoftReference):内存不足时会被 GC 回收
弱引用 (WeakReference):只要发生 GC,就会被回收(即使内存充足)
虚引用 (PhantomReference):用于对象回收跟踪
2.关于ThreadLocal的源码解析:
1.源码的五步解析:
图看不清楚的访问这里:图片
首先最重要的就是弱引用什么时候被回收?,以及他的字段reference:
当发生 GC 时,如果某个对象 只 被
WeakReference
引用(没有强引用指向它),那么:
这个对象的referent
字段会被自动设为null
被引用的对象会被回收
2.注意:这里的魔法
当
Entry
调用super(k)
时:
它调用了父类
WeakReference
的构造函数
k
(ThreadLocal 对象) 被存入继承自Reference
的referent
字段这个
referent
就是 Key 的存储位置!
虽然
Entry
类没有显式声明key
字段,但通过继承,它拥有了referent
字段(来自WeakReference
→Reference
)这个字段就是用来存储 Key (
ThreadLocal
对象)的
3.魔法的实现原理----JVM
WeakReference
类的魔法在 JVM 层面实现:
当 JVM 进行垃圾回收时,会特殊处理
WeakReference
及其子类的referent
字段这个字段的值会被垃圾回收器特殊标记为弱引用
这不是普通的 Java 继承特性,而是 JVM 对
Reference
类族的特殊处理
4.大概这么说:
首先要了解弱引用的法则:当发生 GC 时,如果某个对象 只 被
WeakReference
引用(没有强引用指向它),那么:这个对象的referent
字段会被自动设为null,被
引用的对象会被回收。然后这个Entry继承了
WeakReference
,并且ThreadLocal是被Reference的字段Referent引用着,因此被JVM标记为弱引用。。。当强引用消失后ThreadLocal引用的对象就会被回收。我们的Thread对象最终被referent引用着
5.总结:
- `Entry`的key是通过继承自`WeakReference`的`referent`字段来存储的,并且是弱引用。
- `Entry`的value是通过自己的`value`字段存储,是强引用。
这样设计的主要目的是为了避免内存泄漏:当`ThreadLocal`对象(key)不再被其他地方强引用时,垃圾收集器可以回收这个key,这样`Entry`中的`referent`字段就会变成`null`。
虽然此时`Entry`和`value`还存在(因为`value`是强引用),但`ThreadLocalMap`在后续操作(如get、set、remove)时会自动清理这些key为null的`Entry`,从而避免value的内存泄漏。
最后:
- 强引用 Value: Entry 对 Value 持有强引用,确保只要 Entry 还在 Map 中,Value 就不会被 GC 回收。这是业务逻辑需要的。
- ThreadLocalMap 的设计包含了清理机制: 在调用
ThreadLocal
的get()
,set()
,remove()
方法时,Map 会主动去扫描那些Entry.get() == null
(即 Key 已被回收) 的 Entry,并将这些 Entry 以及它们对应的强引用 Value 清除掉 (value = null
),然后移除这些 Entry。所以我们一般都要显示的调用remove方法。