--- old/src/java.base/share/classes/java/lang/ref/Reference.java 2018-05-25 04:19:20.733521470 -0400 +++ new/src/java.base/share/classes/java/lang/ref/Reference.java 2018-05-25 04:19:20.445506419 -0400 @@ -43,71 +43,146 @@ public abstract class Reference { - /* A Reference instance is in one of four possible internal states: - * - * 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. - * - * Pending: An element of the pending-Reference list, waiting to be - * enqueued by the Reference-handler thread. Unregistered instances - * are never in this state. - * - * 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. - * - * Inactive: Nothing more to do. Once an instance becomes Inactive its - * state will never change again. - * - * The state is encoded in the queue and next fields as follows: - * - * Active: queue = ReferenceQueue with which instance is registered, or - * ReferenceQueue.NULL if it was not registered with a queue; next = - * null. - * - * Pending: queue = ReferenceQueue with which instance is registered; - * next = this - * - * Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance - * in queue, or this if at end of list. - * - * Inactive: queue = ReferenceQueue.NULL; next = this. - * - * 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. - * - * 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. + /* The state of a Reference object is characterized by two attributes. It + * may be either "active", "pending", or "inactive". It may also be + * either "registered", "enqueued", "dequeued", or "unregistered". + * + * 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, the collector + * "notifies" the reference, changing the state to either "pending" or + * "inactive". + * referent != null; discovered = null, or in GC discovered list. + * + * Pending: An element of the pending-Reference list, waiting to be + * processed by the ReferenceHandler thread. The pending-Reference + * list is linked through the discovered fields of references in the + * list. + * referent = null; discovered = next element in pending-Reference list. + * + * Inactive: Neither Active nor Pending. + * referent = null. + * + * Registered: Associated with a queue when created, and not yet added + * to the queue. + * queue = the associated queue. + * + * Enqueued: Added to the associated queue, and not yet removed. + * queue = ReferenceQueue.ENQUEUE; next = next entry in list, or this to + * indicate end of list. + * + * Dequeued: Added to the associated queue and then removed. + * queue = ReferenceQueue.NULL; next = this. + * + * Unregistered: Not associated with a queue when created. + * queue = ReferenceQueue.NULL. + * + * The collector only needs to examine the referent field and the + * discovered field to determine whether a (non-FinalReference) Reference + * object needs special treatment. If the referent is non-null and not + * known to be live, then it may need to be discovered for possible later + * notification. But if the discovered field is non-null, then it has + * already been discovered. + * + * FinalReference (which exists to support finalization) differs from + * other references, because a FinalReference is not cleared when + * notified. The referent being null or not cannot be used to distinguish + * between the active state and pending or inactive states. However, + * FinalReferences do not support enqueue(). Instead, the next field of a + * FinalReference object is set to "this" when it is added to the + * pending-Reference list. The use of "this" as the value of next in the + * enqueued and dequeued states maintains the non-active state. An + * additional check that the next field is null is required to determine + * that a FinalReference object is active. + * + * Initial states: + * [active/registered] + * [active/unregistered] [1] + * + * Transitions: + * clear + * [active/registered] -------> [inactive/registered] + * | | + * | | enqueue [2] + * | GC enqueue [2] | + * | -----------------| + * | | + * v | + * [pending/registered] --- v + * | | ReferenceHandler + * | enqueue [2] |---> [inactive/enqueued] + * v | | + * [pending/enqueued] --- | + * | | poll/remove + * | poll/remove | + * | | + * v ReferenceHandler v + * [pending/dequeued] ------> [inactive/dequeued] + * + * + * clear/enqueue/GC [3] + * [active/unregistered] ------ + * | | + * | GC | + * | |--> [inactive/unregistered] + * v | + * [pending/unregistered] ------ + * ReferenceHandler + * + * Terminal states: + * [inactive/dequeued] + * [inactive/unregistered] + * + * Unreachable states (because enqueue also clears): + * [active/enqeued] + * [active/dequeued] + * + * [1] Unregistered is not permitted for FinalReferences. + * + * [2] These transitions are not possible for FinalReferences, making + * [pending/enqueued] and [pending/dequeued] unreachable, and + * [inactive/registered] terminal. + * + * [3] The garbage collector may directly transition a Reference + * from [active/unregistered] to [inactive/unregistered], + * bypassing the pending-Reference list. */ private T referent; /* Treated specially by GC */ + /* The queue this reference gets enqueued to by GC notification or by + * calling enqueue(). + * + * When registered: the queue with which this reference is registered. + * enqueued: ReferenceQueue.ENQUEUE + * dequeued: ReferenceQueue.NULL + * unregistered: ReferenceQueue.NULL + */ volatile ReferenceQueue queue; - /* When active: NULL - * pending: this - * Enqueued: next reference in queue (or this if last) - * Inactive: this + /* The link in a ReferenceQueue's list of Reference objects. + * + * When registered: null + * enqueued: next element in queue (or this if last) + * dequeued: this (marking FinalReferences as inactive) + * unregistered: null */ @SuppressWarnings("rawtypes") volatile Reference next; - /* 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 + /* Used by the garbage collector to accumulate Reference objects that need + * to be revisited in order to decide whether they should be notified. + * Also used as the link in the pending-Reference list. The discovered + * field and the next field are distinct to allow the enqueue() method to + * be applied to a Reference object while it is either in the + * pending-Reference list or in the garbage collector's discovered set. + * + * When active: null or next element in a discovered reference list + * maintained by the GC (or this if last) + * pending: next element in the pending-Reference list (null if last) + * inactive: null */ - private transient Reference discovered; /* used by VM */ + private transient Reference discovered; /* High-priority thread to enqueue pending References @@ -141,17 +216,17 @@ } /* - * Atomically get and clear (set to null) the VM's pending list. + * Atomically get and clear (set to null) the VM's pending-Reference list. */ private static native Reference getAndClearReferencePendingList(); /* - * Test whether the VM's pending list contains any entries. + * Test whether the VM's pending-Reference list contains any entries. */ private static native boolean hasReferencePendingList(); /* - * Wait until the VM's pending list may be non-null. + * Wait until the VM's pending-Reference list may be non-null. */ private static native void waitForReferencePendingList();