Java ~ Reference【源码】

前言


 文章

一 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);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

说淑人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值