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

Print this page

        

@@ -24,10 +24,12 @@
  */
 
 package java.lang.ref;
 
 import sun.misc.Cleaner;
+import sun.misc.JavaLangRefAccess;
+import sun.misc.SharedSecrets;
 
 /**
  * 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

@@ -145,11 +147,33 @@
         ReferenceHandler(ThreadGroup g, String name) {
             super(g, name);
         }
 
         public void run() {
-            for (;;) {
+            while (true) {
+                tryHandlePending(true);
+            }
+        }
+    }
+
+    /**
+     * 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) {

@@ -161,37 +185,39 @@
                             pending = r.discovered;
                             r.discovered = null;
                         } else {
                             // The waiting on the lock may cause an OutOfMemoryError
                             // because it may try to allocate exception objects.
+                    if (waitForNotify) {
                             lock.wait();
-                            continue;
+                    }
+                    // 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...
                     Thread.yield();
                     // retry
-                    continue;
+            return true;
                 } catch (InterruptedException x) {
                     // retry
-                    continue;
+            return true;
                 }
 
                 // Fast path for cleaners
                 if (c != null) {
                     c.clean();
-                    continue;
+            return true;
                 }
 
-                ReferenceQueue<Object> q = r.queue;
+        ReferenceQueue<? super Object> q = r.queue;
                 if (q != ReferenceQueue.NULL) q.enqueue(r);
-            }
-        }
+        return true;
     }
 
     static {
         ThreadGroup tg = Thread.currentThread().getThreadGroup();
         for (ThreadGroup tgn = tg;

@@ -202,12 +228,19 @@
          * 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);
+            }
+        });
+    }
 
     /* -- Referent accessor and setters -- */
 
     /**
      * Returns this reference object's referent.  If this reference object has