< prev index next >

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

Print this page

        

@@ -23,10 +23,13 @@
  * questions.
  */
 
 package java.lang.ref;
 
+import sun.misc.Unsafe;
+import java.util.function.Consumer;
+
 /**
  * Reference queues, to which registered reference objects are appended by the
  * garbage collector after the appropriate reachability changes are detected.
  *
  * @author   Mark Reinhold

@@ -81,10 +84,14 @@
         if (r != null) {
             head = (r.next == r) ?
                 null :
                 r.next; // Unchecked due to the next field having a raw type in Reference
             r.queue = NULL;
+            // make sure the store to r.next below doesn't float up
+            // before the store to r.queue above because we need this
+            // for correct lock-less iteration in forEach()
+            U.storeFence();
             r.next = r;
             queueLength--;
             if (r instanceof FinalReference) {
                 sun.misc.VM.addFinalRefCount(-1);
             }

@@ -162,6 +169,40 @@
      */
     public Reference<? extends T> remove() throws InterruptedException {
         return remove(0);
     }
 
+    /**
+     * Iterate queue and invoke given action with each Reference.
+     * Suitable for diagnostic purposes.
+     * WARNING: any use of this method should make sure to not
+     * retain the referents of iterated references (in case of
+     * FinalReference(s)) so that their life is not prolonged more
+     * than necessary.
+     */
+    void forEach(Consumer<? super Reference<? extends T>> action) {
+        for (Reference<? extends T> r = head; r != null;) {
+            action.accept(r);
+            Reference rn = r.next;
+            // make sure load of r.queue below doesn't float up before
+            // the load of r.next above. The corresponding stores are
+            // performed in reallyPoll() in reverse order.
+            U.loadFence();
+            if (rn == r) {
+                if (r.queue == ENQUEUED) {
+                    // still enqueued -> we reached end of chain
+                    r = null;
+                } else {
+                    // already dequeued: r.queue == NULL; ->
+                    // restart from head when overtaken by queue poller(s)
+                    r = head;
+                }
+            } else {
+                // next in chain
+                r = rn;
+            }
+        }
+    }
+
+    /* we need a fence */
+    private static final Unsafe U = Unsafe.getUnsafe();
 }
< prev index next >