前言
文章
- 相关系列:《Java ~ Reference【目录】》(持续更新)
- 相关系列:《Java ~ Reference【源码】》(学习过程/多有漏误/仅作参考/不再更新)
- 相关系列:《Java ~ Reference【总结】》(学习总结/最新最准/持续更新)
- 相关系列:《Java ~ Reference【问题】》(学习解答/持续更新)
- 涉及内容:《Java ~ Reference ~ ReferenceQueue【总结】》
- 涉及内容:《Java ~ Reference ~ SoftReference【总结】》
- 涉及内容:《Java ~ Reference ~ WeakReference【总结】》
- 涉及内容:《Java ~ Reference ~ PhantomReference【总结】》
- 涉及内容:《Java ~ Reference ~ Cleaner【总结】》
- 涉及内容:《Java ~ Reference ~ FinalReference【总结】》
- 涉及内容:《Java ~ Reference ~ Finalizer【总结】》
一 Referecne(引用)抽象类源码及机制详解
抽象类
在JDK1.2之前,Java中引用的定义是十分传统的:如果引用类型的变量中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。在这种定义之下,一个对象只有被引用和没有被引用两种状态。
实际上,我们还希望存在这样的一类对象:当内存空间还足够的时候,这些对象能够保留在内存空间中;如果当内存空间在进行了垃圾收集之后还是非常紧张,则可以抛弃这些对象。基于这种特性,可以满足很多系统缓存功能的使用场景。
从JDK1.2起,Java对引用概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)及终引用(Final Reference)。其中强引用就是JDK1.2之前的引用,日常代码中绝大多数引用都是强引用。而其它几种引用则是JDK1.2中引入的,这些引用有着各自的特性及作用,例如软引用就代表了上述需求的“将对象在内存空闲时保留,不足时舍弃”的功能。这些引用概念存在着相应的类实现,Java通过Java类与底层机制相结合的方式实现了这些概念,而重点是这些类又全都继承自同一个父类,也是本文真正的核心 —— Referecne(引用)抽象类(下文简称引用)。
引用抽象类是强引用之外引用(下文简称特殊引用)概念的实质化产物,其作用在于定义并实现了特殊引用的生命周期及运行流程,使得特殊引用不再是一个虚幻的设想,而是实际独立于强/无引用之外的第三存在,为软、弱等具体特殊引用实现提供了实质性基础,该知识点会在下文详述。
/**
* Abstract base class for reference objects. This class defines the
* operations common to all reference objects. Because reference objects are
* implemented in close cooperation with the garbage collector, this class may
* not be subclassed directly.
* 引用对象的抽象基类。该类定义了所有引用对象的通用操作。
* 因为引用对象是与垃圾收集器密切合作实现的,所以不能直接对该类进行子类化。
*
* @author Mark Reinhold
* @Description: 引用类,是所有引用类的父类,定义了强引用之外引用概念。
* @since 1.2
*/
public abstract class Reference<T> {
...
}
字段
referent(所指对象) —— Referecne(引用)类对象关联的具体对象,意味着该对象具有了特殊引用,会收到GC的特殊处理。
*
* @Description: 所指对象,即具体关注其引用关系的对象。
*/
private T referent; /* Treated specially by GC */
queue(引用队列) —— 专门与Referecne(引用)类配合使用的队列,如果Referecne(引用)类对象注册了引用队列(即queue(引用队列)字段不为null),则其会在所指对象被GC回收时加入引用队列,此时开发者就可以通过获取引用队列中Referecne(引用)类对象判断其对应的所指对象是否被GC回收,并同时可以在此时机执行一些自定义的操作。除此以外,queue(引用队列)字段还被用于与next(下个引用)字段相配合表示Referecne(引用)类对象的状态,这是一个未通过具体字段实现的概念。除此之外,该值还被用于判断当前Referecne(引用)类对象是否已被加入引用队列中。当Referecne(引用)类对象被加入/移除其注册的引用队列后,会将该字段值设置为“入队”引用队列/“空”引用队列,因此该字段可作为判断Referecne(引用)类对象是否出/入队的标志。
/**
* @Description: 引用队列,如果引用队列存在,则所指对象被GC回收后,会将对应的引用对象存入到引用队列中。
*/
volatile ReferenceQueue<? super T> queue;
next(下个引用) —— 当Referecne(引用)类对象位于引用队列时用于持有后继Referecne(引用)类对象的引用。除此以外,next(下个引用)字段还被用于与queue(引用队列)字段相配合表示Referecne(引用)类对象的状态,这是一个未通过具体字段实现的概念。
/**
* When active: NULL
* pending: this
* Enqueued: next reference in queue (or this if last)
* Inactive: this
* 活动:null;
* 待定:自身;
* 入队:引用队列中后继引用对象的引用,如果当前引用对象是引用队列中的最后一个节点,则指向自身;
* 怠惰:自身。
*/
@SuppressWarnings("rawtypes")
volatile Reference next;
discovered(发现引用) —— 当Referecne(引用)类对象位于发现/待定列表时用于持有后继Referecne(引用)类对象的引用(如果是发现列表中的最后一个元素,值为自身。如果是待定列表中的最后一个元素,值为null)。发现列表是一个由GC负责维护的列表,目前还没有找到相关资料描述,但个人猜测可能与GC的可达性分析有关。当Referecne(引用)类对象为active(活动)状态是其值为发现列表中的后继Referecne(引用)类对象的引用,因此可知Referecne(引用)类对象被创建之时就被加入了发现列表。
/**
* When active: next element in a discovered reference list maintained by GC (or this if last)
* pending: next element in the pending list (or null if last)
* otherwise: NULL
* 活动:由GC负责维护的发现列表中的后继引用对象的引用,如果当前引用对象是发现列表中的最后一个节点,则指向自身;
* 待定:待定列表中的后继引用对象的引用,如果当前引用对象是待定列表中的最后一个节点,则为null;
* 否则:null。
*/
transient private Reference<T> discovered; /* used by VM */
lock(锁) —— 该字段值用于访问待定列表时作为同步手段的锁对象使用。该字段是一个私有的静态变量,因此可知是一个类锁。
/**
* Object used to synchronize with the garbage collector. The collector
* must acquire this lock at the beginning of each collection cycle. It is
* therefore critical that any code holding this lock complete as quickly
* as possible, allocate no new objects, and avoid calling user code.
*
* @Description: 锁类
*/
static private class Lock {
}
/**
* @Description: 静态类型的锁对象,用于加类锁
*/
private static Lock lock = new Lock();
pending(待定引用) —— 待定列表的头Referecne(引用)类对象。待定列表不是一个真正意义上列表对象,而是一个通过链接组成的概念列表,而pending(待定引用)字段便表示其头Referecne(引用)类对象,因此可知只要获得了头Referecne(引用)类对象就相当于获得了整个待定列表。pending(待定引用)字段是一个私有的静态变量,因此可知整个JVM中就只有一个待定列表,且该字段由GC负责赋值。
待定列表用于保存处于active(活动)状态且注册了引用队列的Referecne(引用)类对象。Referecne(引用)类对象一开始会存在于发现列表中,GC会将其中需要执行Referecne(引用)类机制的对象挑选出来置入待定列表中,以供“引用处理器”线程进行处理。
/**
* List of References waiting to be enqueued. The collector adds
* References to this list, while the Reference-handler thread removes
* them. This list is protected by the above lock object. The
* list uses the discovered field to link its elements.
* 等待加入引用队列的引用对象。由收集器负责将引用对象加入该队列中,直到引用处理器线程将之移除。
* 该列表受上述锁对象保护(即类锁)。该列表通过"discovered"字段链接其的元素。
*/
private static Reference<Object> pending = null;
state(状态) —— Referecne(引用)类存在状态的概念,但这个概念并没有采用类似于state的字段直接实现,而是通过组合判断queue(引用队列)字段及next(下个引用)字段在不同状态下的值来表现的。相关的状态及源码注释如下:
active(活动):active(活动)状态是Referecne(引用)类对象的初始状态,这个状态下的Referecne(引用)类对象会受到GC的“特殊照顾”。当对象被判定为可回收后,如果该Referecne(引用)类对象注册了引用队列,GC会将之加入到待定队列中(加入引用队列的前置操作),相当于将状态修改为了pending(待定)。而如果Referecne(引用)类对象没有注册引用队列的话则会直接将其状态变为inactive(怠惰)。当Referecne(引用)类对象的状态为active(活动)时,queue(引用队列)字段及next(下个引用)字段的值如下:
queue(引用队列):自注册的引用队列对象或默认的"空"引用队列对象(如果为注册引用队列,会赋予一个默认的"空"引用队列对象表示未注册);
next(下个引用):null(active(活动)是唯一一个“next”字段为null的状态,因此可以直接通过判断“next”字段是否为null来判断其是否为active(活动)状态)。
pending(待定):当Referecne(引用)类对象被GC加入待定列表时,即表示其状态变为了pending(待定)状态,这个状态下的Referecne(引用)类对象正等待着被“引用处理器”线程加入到引用队列中。由于加入待定列表是将Referecne(引用)类对象加入到引用队列的前置步骤,因此可知只有注册了引用队列的Referecne(引用)类对象才能够转变为这个状态。当Referecne(引用)类对象的状态为pending(待定)时,queue(引用队列)字段及next(下个引用)字段的值如下:
queue(引用队列):自注册的引用队列对象(pending(待定)状态下的Referecne(引用)类对象必然注册了引用队列);
next(下个引用):this(即当前Referecne(引用)类对象,是专门为了区分状态而赋的值)。
enqueue(入队):当Referecne(引用)类对象被“引用处理器”线程加入自注册的引用队列时,即表示其状态变为了enqueue(入队)状态,这个状态下的Referecne(引用)类对象正等待着被用户线程从引用队列中取出并执行相应的操作(开发者自定义)。当enqueue(入队)状态下的Referecne(引用)类对象被用户线程从引用队列移除时,意味着其变为了inactive(怠惰)状态,同时也意味着一个Referecne(引用)类对象可能永远都不会变为inactive(怠惰)…如果其永远都没有出队的话。当Referecne(引用)类对象的状态为enqueue(入队)时,queue(引用队列)字段及next(下个引用)字段的值如下:
queue(引用队列):“入队”引用队列对象(一个与“空”引用队列对象相同的预定值,表示当前Referecne(引用)类对象已经加入的引用队列,可用做Referecne(引用)类对象是否入队的判断条件);
next(下个引用):引用队列中后继Referecne(引用)类对象的引用。
inactive(怠惰):Referecne(引用)类对象转变为inactive(怠惰)状态有两种方式:一是因为没有注册引用队列而被GC设置;二是其从引用队列中出队时被用户线程设置。一个状态已经被转变为inactive(怠惰)的Referecne(引用)类对象意味着其已经没有什么事情可以做了,处于生命周期的尾声,存在的唯一意义就是等待被GC回收。当Referecne(引用)类对象的状态为inactive(怠惰)时,queue(引用队列)字段及next(下个引用)字段的值如下:
queue(引用队列):"空"引用队列对象("空"引用队列对象即是Referecne(引用)类对象未注册引用队列的默认值,也是其从引用队列中出队时会被赋予的终结值,因此"空"引用队列对象有着双重含义);
next(下个引用):this(即当前Referecne(引用)类对象,是专门为了区分状态而赋的值)。
/**
* A Reference instance is in one of four possible internal states:
* 引用对象可能处于以下四种内部状态之一:
* <p>
* Active: Subject to special treatment by the garbage collector. Some
* time after the collector detects that the reachability of the
* referent has changed to the appropriate state, it changes the
* instance's state to either Pending or Inactive, depending upon
* whether or not the instance was registered with a queue when it was
* created. In the former case it also adds the instance to the
* pending-Reference list. Newly-created instances are Active.
* 活动:受到GC的特殊处理(引用对象本身就区别于常规对象,其是专用于实现与GC密切相关的引用关系的,这代表GC的运行对其存在依赖
* 关系,因此对其的处理自然不可能与常规对象等同。GC对引用对象的特殊处理主要有两点:一是可达性分析,如果在可达性分析的过程中追
* 踪到了引用对象,那么对其所指对象的回收判断必然会产生影响。例如一个软引用对象可能会使得GC对所指对象的存活时间进行计算,以判
* 断其保留或回收。二是对引用对象的后续处理,例如将之加入到引用队列中。但无论是哪一种都有一个前提,即引用对象必须是"活动"状态。
* 因为对于前者,只有"活动"状态才表示其所指对象未被判定为可回收。而对于后者,也只有"活动"状态才表示其自身还未被告知应执行加入引用
* 队列的流程。因此对于GC而言,只有"活动"状态的引用对象才有意义,否则其也就是个可达性分析中的中转站或终点而已。)。在GC检测到
* 所指对象的可达性已更改为适当状态(即可回收)的一段时间后,它会将引用对象的状态更改为"待定"或"怠惰",这取决于该引用对象在创建时
* 是否注册引用队列。在前一种情况下(待定),GC还会将引用对象添加到待定列表中。新创建的实例是"活动"的。
* <p>
* Pending: An element of the pending-Reference list, waiting to be
* enqueued by the Reference-handler thread. Unregistered instances
* are never in this state.
* 待定:一个待定列表的元素(即当前引用对象已经加入待定列表),
* 正等待着被"引用处理器"线程入队(即加入引用队列)。
* 没有注册引用队列的引用对象永远不会处于这个状态。
* <p>
* Enqueued: An element of the queue with which the instance was
* registered when it was created. When an instance is removed from
* its ReferenceQueue, it is made Inactive. Unregistered instances are
* never in this state.
* 入队:一个引用对象创建时注册的引用队列的元素(即当前对象已被加入引用队列)。
* 当引用对象从它的引用队列中删除时,它会变为"怠惰"。
* 没有注册引用队列的引用对象永远不会处于这个状态。
* <p>
* Inactive: Nothing more to do. Once an instance becomes Inactive its
* state will never change again.
* 怠惰:没有什么可做的。一旦一个引用对象变为"怠惰"状态将永远不会再改变。
* "怠惰"状态的改变有两种情况:
* 未注册引用队列:活动(初始状态) - > 怠惰(最终状态 —— 未加入引用队列)
* 已注册引用队列:活动(初始状态) -> 待定(已加入待定列表) -> 入队(已加入引用队列) -> (最终状态 —— 已退出引用队列)
* <p>
* The state is encoded in the queue and next fields as follows:
* 状态在引用队列及"next"字段中的编码如下:
* Reference类并没定义具体的状态字段及状态值,因此其具体的判断通过"queue"及"next"两个字段组合实现。
* <p>
* Active: queue = ReferenceQueue with which instance is registered, or
* ReferenceQueue.NULL if it was not registered with a queue; next =
* null.
* 活动:当引用对象处于"活动"状态时,"queue"字段为引用对象注册的引用队列或默认"空"引用队列(如果没有注册引用队列会默认给予一个
* 空队列)。而"next"字段为null。"next"字段是用于记录引用对象在引用队列中的后继引用对象的,一个没有注册引用队列的引用对象自然不
* 会有后继引用对象。
* <p>
* Pending: queue = ReferenceQueue with which instance is registered;
* next = this
* 待定:当引用对象处于"待定"状态时,"queue"字段为引用对象注册的引用队列(只有注册了引用队列的引用对象才能变为"待定"状态)。而
* "next"字段为当前引用对象,用于GC作为状态判断的标志。此处"next"字段的修改是由GC完成的,可以看到"next"是一个私有字段,并且不
* 存在set()方法,因此其的赋值应该是通过反射机制实现的。
* <p>
* Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
* in queue, or this if at end of list.
* 入队:当引用对象处于"入队"状态时,"queue"字段为"入队"引用队列,这个队列与"空"引用队列一样都是一个预定值,一旦引用对象被加入到
* 其注册的引用队列中后,"queue"字段就会被替换为"入队"引用队列表示其已经成功入队。而"next"字段为其在引用队列中的后继引用对象或其
* 本身(如果是第一个入队的引用对象的话)。
* <p>
* 怠惰:当引用对象处于"怠惰"状态时,"queue"字段为"空"引用队列。"空"引用队列表示其未注册引用队列或已经从注册的引用队列中出队。而
* "next"字段为当前引用对象。
* Inactive: queue = ReferenceQueue.NULL; next = this.
* <p>
* With this scheme the collector need only examine the next field in order
* to determine whether a Reference instance requires special treatment: If
* the next field is null then the instance is active; if it is non-null,
* then the collector should treat the instance normally.
* 根据方案GC只需要检查"next"字段,以确定引用对象是否需要特殊处理:如果"next"字段为null则表示引用对象的状态为"活动"(表示需要进行
* 特殊处理,即将引用对象加入到引用队列中);如果"next"字段不为null,则GC应该正常处理。
* <p>
* To ensure that a concurrent collector can discover active Reference
* objects without interfering with application threads that may apply
* the enqueue() method to those objects, collectors should link
* discovered objects through the discovered field. The discovered
* field is also used for linking Reference objects in the pending list.
* 为了确保并发收集器能够发现"活动"状态的引用对象而不会干扰可能对这些对象应用enqueue()方法的应用程序线程(即引用处理器线程),收
* 集器应该通过"discovered"字段链接已发现的对象。"discovered"字段还用于链接待定列表中的引用对象。
*/
静态块
在Referecne(引用)类的静态块中创建了一条引用处理器线程。该线程是Referecne(引用)类的内部类ReferenceHandler(引用处理器)类的实例,专用于执行Referecne(引用)机制,因此可知整个Referecne(引用)机制都是通过这一条线程来执行的。该线程是一条守护线程,优先级被设置为了10(最高),目的是尽可能多的获取CPU资源。
static {
// 获取当前线程所在的线程组。
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent())
;
// 实例化一个引用处理线程,该线程是一个守护线程,并且是最高的优先级。该线程专用于将等待列表中的引用对象添加到引用队列中。
Thread handler = new ReferenceHandler(tg, "Reference Handler");
/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
// provide access in SharedSecrets
// 作用未知。
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
@Override
public boolean tryHandlePendingReference() {
return tryHandlePending(false);
}
});
}
构造方法
Reference(T referent)/Reference(T referent, ReferenceQueue<? super T> queue) —— Referecne(引用)类有两个构造方法,对应着两种仅有的使用场景(注册/不注册引用队列)。无论是Referecne(引用)类还是其子类,所指对象是创建对象时必须指定的,毕竟如果连特殊引用所属的对象都没有的话,Referecne(引用)类对象还有什么意义呢?两个方法的访问权限都是DEFAULT,因此可知开发者是无法直接通过new关键字创建其对象的。
Reference(T referent) {
this(referent, null);
}
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
方法
public T get() —— 获取 —— 该方法用于获取Referecne(引用)类对象对应的所指对象,所指对象不存在时会返回null,例如所指对象已经被GC回收。
/**
* Returns this reference object's referent. If this reference object has
* been cleared, either by the program or by the garbage collector, then
* this method returns <code>null</code>.
*
* @return The object to which this reference refers, or
* <code>null</code> if this reference object has been cleared
*/
public T get() {
return this.referent;
}
public void clear() —— 清除 —— 该方法会将Referecne(引用)类对象对应的所指对象清除,即断开两者的引用关系,并且也不会将Referecne(引用)类对象加入到引用队列中。该方法是专门给Java代码使用的,GC会直接通过底层断开两者的引用关系,而不会调用此方法。
/**
* Clears this reference object. Invoking this method will not cause this
* object to be enqueued.
*
* <p> This method is invoked only by Java code; when the garbage collector
* clears references it does so directly, without invoking this method.
*/
public void clear() {
this.referent = null;
}
public boolean isEnqueued() —— 是否入队(false:否,true:是) —— 判断当前Referecne(引用)类对象是否已加入引用队列。Referecne(引用)类对象加入引用队列时会将queue(引用队列)字段的值设置为“入队”引用队列对象,因此判断Referecne(引用)类对象是否加入引用队列无需遍历引用队列,直接判断queue(引用队列)字段的值是否是“入队”引用队列对象即可。
/**
* Tells whether or not this reference object has been enqueued, either by
* the program or by the garbage collector. If this reference object was
* not registered with a queue when it was created, then this method will
* always return <code>false</code>.
*
* @return <code>true</code> if and only if this reference object has
* been enqueued
*/
public boolean isEnqueued() {
return (this.queue == ReferenceQueue.ENQUEUED);
}
public boolean enqueue() —— 入队(false:失败,true:成功) —— 将当前Referecne(引用)类对象加入引用队列,底层调用引用队列的enqueue()方法实现。该方法是专门给Java代码使用的,“引用处理器”线程会直接调用引用队列的enqueue()方法将Referecne(引用)类对象加入引用队列。
/**
* Adds this reference object to the queue with which it is registered,
* if any.
*
* <p> This method is invoked only by Java code; when the garbage collector
* enqueues references it does so directly, without invoking this method.
*
* @return <code>true</code> if this reference object was successfully
* enqueued; <code>false</code> if it was already enqueued or if
* it was not registered with a queue when it was created
*/
public boolean enqueue() {
return this.queue.enqueue(this);
}
static boolean tryHandlePending(boolean waitForNotify) —— 尝试处理待定列表(false:失败,true:成功) —— 该方法实现了Referecne(引用)类对象的运行流程,是Referecne(引用)机制的核心内容,因此需要重点学习。该方法的主要内容是将Referecne(引用)类对象从待定列表迁移至引用队列中,在此过程中存在一个特殊判断:即如果从Referecne(引用)类对象是其子孙类Cleaner(清洁工)类(该类是Referecne(引用)类的直接子类PhantomReferecne(虚引用)类的直接子类,在设计上用于对资源进行回收)的对象,则只会执行其自定义操作,而不会将之加入引用队列中。
/**
* Try handle pending {@link Reference} if there is one.<p>
* Return {@code true} as a hint that there might be another
* {@link Reference} pending or {@code false} when there are no more pending
* {@link Reference}s at the moment and the program can do some other
* useful work instead of looping.
*
* @param waitForNotify if {@code true} and there was no pending
* {@link Reference}, wait until notified from VM
* or interrupted; if {@code false}, return immediately
* when there is no pending {@link Reference}.
* @return {@code true} if there was a {@link Reference} pending and it
* was processed, or we waited for notification and either got it
* or thread was interrupted before being notified;
* {@code false} otherwise.
*/
static boolean tryHandlePending(boolean waitForNotify) {
Reference<Object> r;
Cleaner c;
try {
// 在类锁的保护下执行,因此是线程安全的。
synchronized (lock) {
if (pending != null) {
// 如果待定引用不为null,说明已经有引用对象被GC加入到了待定列表中,获取待定引用(快照)。
r = pending;
// 'instanceof' might throw OutOfMemoryError sometimes
// so do this before un-linking 'r' from the 'pending' chain...
// 如果待定引用(快照)是清洁工类型,则获取清洁工(快照)。
c = r instanceof Cleaner ? (Cleaner) r : null;
// unlink 'r' from 'pending' chain
// 设置待定引用为待定引用(快照)的发现引用,设置待定引用(快照)的发现引用为null。该操作的本质实际上就是待定列表的移除
// 头引用对象并解除其与待定列表关系的过程。
pending = r.discovered;
r.discovered = null;
} else {
// The waiting on the lock may cause an OutOfMemoryError
// because it may try to allocate exception objects.
// 如果待定引用为null,则说明还没有引用对象被GC纳入等待列表中。如果waitForNotify为true,则将当前线程挂起,直至被唤醒或中
// 断,目的是等待待定引用的到来。
if (waitForNotify) {
lock.wait();
}
// retry if waited
return waitForNotify;
}
}
} catch (OutOfMemoryError x) {
// Give other threads CPU time so they hopefully drop some live references
// and GC reclaims some space.
// Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
// persistently throws OOME for some time...
// 放弃当前的CPU资源,给其他线程一些时间释放一些引用。
Thread.yield();
// retry
return true;
} catch (InterruptedException x) {
// retry
return true;
}
// Fast path for cleaners
// 如果待定引用(快照)是清洁工对象,则直接清理,即完成相关的处理后返回成功。待定引用(快照)不会被加入到引用队列中。
if (c != null) {
c.clean();
return true;
}
// 获取待定引用(快照)的引用队列,并判断引用队列是否合法,即是否是一个真正的引用队列,如果是则直接将引用对象入队。
ReferenceQueue<? super Object> q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
return true;
}
二 ReferenceHandler(引用处理器)类源码及机制详解
类
ReferenceHandler(引用处理器)类是Referecne(引用)类的一个静态内部类,继承自Thread(线程)类,因此可知该类的实例是一个线程。该类只有一个实例,也就是上文已经提及的“引用处理器”线程,该线程是拥有最高优先级的守护线程,专用于执行Referecne(引用)机制。
/**
* High-priority thread to enqueue pending References
*
* @Description: 引用处理器类,该类继承于线程类,因此其就是一个线程。
*/
private static class ReferenceHandler extends Thread {
...
}
静态块
预加载了两个所需的类…具体效果不是很清楚。
static {
// pre-load and initialize InterruptedException and Cleaner classes
// so that we don't get into trouble later in the run loop if there's
// memory shortage while loading/initializing them lazily.
// 预加载InterruptedException与Cleaner两个类。
ensureClassInitialized(InterruptedException.class);
ensureClassInitialized(Cleaner.class);
}
/**
* @Description: 确保类初始化
*/
private static void ensureClassInitialized(Class<?> clazz) {
try {
// 加载一个指定的类,即完成加载 - > 校验 - > 准备 - > 解析 - > 初始化。在第二个参数中传入了true,因此会执行类加载操作中的初始化操作,
// 即执行指定类的静态代码块。
Class.forName(clazz.getName(), true, clazz.getClassLoader());
} catch (ClassNotFoundException e) {
throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
}
}
构造方法
ReferenceHandler(ThreadGroup g, String name) —— 调用父类Thread(线程)类的构造方法。
/**
* @Description: 构造方法
*/
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
方法
public void run() —— 执行 —— 无限调用tryHandlePending()方法对待定列表中的Referecne(引用)类对象进行处理(加入引用队列中)。
/**
* @Description: 执行
*/
@Override
public void run() {
// 死循环,这表示一旦开始就会永远运行,直至程序结束。
while (true) {
// 将待定状态的引用对象加入引用队列中。
tryHandlePending(true);
}
}