< prev index next >

src/java.base/share/classes/java/lang/ref/Reference.java

Print this page
rev 50107 : [mq]: pp2_work
rev 50108 : [mq]: tschatzl_1
rev 50109 : [mq]: mr_comments
rev 50110 : [mq]: mandy_1

@@ -41,75 +41,150 @@
  * @since    1.2
  */
 
 public abstract class Reference<T> {
 
-    /* A Reference instance is in one of four possible internal states:
+    /* 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, 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.
+     *   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
-     *     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.
+     *   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<? super T> 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<T> discovered;  /* used by VM */
+    private transient Reference<T> discovered;
 
 
     /* High-priority thread to enqueue pending References
      */
     private static class ReferenceHandler extends Thread {

@@ -139,21 +214,21 @@
             }
         }
     }
 
     /*
-     * 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<Object> 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();
 
     private static final Object processPendingLock = new Object();
     private static boolean processPendingActive = false;
< prev index next >