< prev index next >

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

Print this page




  93 
  94     private T referent;         /* Treated specially by GC */
  95 
  96     volatile ReferenceQueue<? super T> queue;
  97 
  98     /* When active:   NULL
  99      *     pending:   this
 100      *    Enqueued:   next reference in queue (or this if last)
 101      *    Inactive:   this
 102      */
 103     @SuppressWarnings("rawtypes")
 104     volatile Reference next;
 105 
 106     /* When active:   next element in a discovered reference list maintained by GC (or this if last)
 107      *     pending:   next element in the pending list (or null if last)
 108      *   otherwise:   NULL
 109      */
 110     private transient Reference<T> discovered;  /* used by VM */
 111 
 112 
 113     /* Object used to synchronize with the garbage collector.  The collector
 114      * must acquire this lock at the beginning of each collection cycle.  It is
 115      * therefore critical that any code holding this lock complete as quickly
 116      * as possible, allocate no new objects, and avoid calling user code.
 117      */
 118     private static class Lock { }
 119     private static Lock lock = new Lock();
 120 
 121 
 122     /* List of References waiting to be enqueued.  The collector adds
 123      * References to this list, while the Reference-handler thread removes
 124      * them.  This list is protected by the above lock object. The
 125      * list uses the discovered field to link its elements.
 126      */
 127     private static Reference<Object> pending = null;
 128 
 129     /* High-priority thread to enqueue pending References
 130      */
 131     private static class ReferenceHandler extends Thread {
 132 
 133         private static void ensureClassInitialized(Class<?> clazz) {
 134             try {
 135                 Class.forName(clazz.getName(), true, clazz.getClassLoader());
 136             } catch (ClassNotFoundException e) {
 137                 throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
 138             }
 139         }
 140 
 141         static {
 142             // pre-load and initialize InterruptedException and Cleaner classes
 143             // so that we don't get into trouble later in the run loop if there's
 144             // memory shortage while loading/initializing them lazily.
 145             ensureClassInitialized(InterruptedException.class);
 146             ensureClassInitialized(Cleaner.class);
 147         }
 148 
 149         ReferenceHandler(ThreadGroup g, String name) {
 150             super(g, null, name, 0, false);
 151         }
 152 
 153         public void run() {
 154             while (true) {
 155                 tryHandlePending(true);
 156             }
 157         }
 158     }
 159 
 160     /**
 161      * Try handle pending {@link Reference} if there is one.<p>
 162      * Return {@code true} as a hint that there might be another
 163      * {@link Reference} pending or {@code false} when there are no more pending
 164      * {@link Reference}s at the moment and the program can do some other
 165      * useful work instead of looping.
 166      *
 167      * @param waitForNotify if {@code true} and there was no pending
 168      *                      {@link Reference}, wait until notified from VM
 169      *                      or interrupted; if {@code false}, return immediately
 170      *                      when there is no pending {@link Reference}.
 171      * @return {@code true} if there was a {@link Reference} pending and it
 172      *         was processed, or we waited for notification and either got it
 173      *         or thread was interrupted before being notified;
 174      *         {@code false} otherwise.
 175      */
 176     static boolean tryHandlePending(boolean waitForNotify) {
 177         Reference<Object> r;
 178         Cleaner c;
 179         try {
 180             synchronized (lock) {
 181                 if (pending != null) {
 182                     r = pending;
 183                     // 'instanceof' might throw OutOfMemoryError sometimes
 184                     // so do this before un-linking 'r' from the 'pending' chain...
 185                     c = r instanceof Cleaner ? (Cleaner) r : null;
 186                     // unlink 'r' from 'pending' chain
 187                     pending = r.discovered;
 188                     r.discovered = null;
 189                 } else {
 190                     // The waiting on the lock may cause an OutOfMemoryError
 191                     // because it may try to allocate exception objects.
 192                     if (waitForNotify) {
 193                         lock.wait();
 194                     }
 195                     // retry if waited
 196                     return waitForNotify;
 197                 }
 198             }
 199         } catch (OutOfMemoryError x) {
 200             // Give other threads CPU time so they hopefully drop some live references
 201             // and GC reclaims some space.
 202             // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
 203             // persistently throws OOME for some time...
 204             Thread.yield();
 205             // retry
 206             return true;
 207         } catch (InterruptedException x) {
 208             // retry
 209             return true;
 210         }
 211 










 212         // Fast path for cleaners
 213         if (c != null) {
 214             c.clean();
 215             return true;






 216         }
 217 

 218         ReferenceQueue<? super Object> q = r.queue;
 219         if (q != ReferenceQueue.NULL) q.enqueue(r);




 220         return true;
 221     }
 222 
 223     static {
 224         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 225         for (ThreadGroup tgn = tg;
 226              tgn != null;
 227              tg = tgn, tgn = tg.getParent());
 228         Thread handler = new ReferenceHandler(tg, "Reference Handler");
 229         /* If there were a special system-only priority greater than
 230          * MAX_PRIORITY, it would be used here
 231          */
 232         handler.setPriority(Thread.MAX_PRIORITY);
 233         handler.setDaemon(true);
 234         handler.start();
 235 
 236         // provide access in SharedSecrets
 237         SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
 238             @Override
 239             public boolean tryHandlePendingReference() {




  93 
  94     private T referent;         /* Treated specially by GC */
  95 
  96     volatile ReferenceQueue<? super T> queue;
  97 
  98     /* When active:   NULL
  99      *     pending:   this
 100      *    Enqueued:   next reference in queue (or this if last)
 101      *    Inactive:   this
 102      */
 103     @SuppressWarnings("rawtypes")
 104     volatile Reference next;
 105 
 106     /* When active:   next element in a discovered reference list maintained by GC (or this if last)
 107      *     pending:   next element in the pending list (or null if last)
 108      *   otherwise:   NULL
 109      */
 110     private transient Reference<T> discovered;  /* used by VM */
 111 
 112 
 113     /* Blocks until the reference pending list becomes non-empty and
 114      * returns the list.


 115      */
 116     private static native Reference<Object> getReferencePendingList();

 117 
 118 







 119     /* High-priority thread to enqueue pending References
 120      */
 121     private static class ReferenceHandler extends Thread {
 122 
 123         private static void ensureClassInitialized(Class<?> clazz) {
 124             try {
 125                 Class.forName(clazz.getName(), true, clazz.getClassLoader());
 126             } catch (ClassNotFoundException e) {
 127                 throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
 128             }
 129         }
 130 
 131         static {
 132             // pre-load and initialize Cleaner class so that we don't get into trouble later in
 133             // the run loop if there's memory shortage while loading/initializing them lazily.


 134             ensureClassInitialized(Cleaner.class);
 135         }
 136 
 137         ReferenceHandler(ThreadGroup g, String name) {
 138             super(g, null, name, 0, false);
 139         }
 140 
 141         public void run() {
 142             while (true) {
 143                 tryHandlePending(true);
 144             }
 145         }
 146     }
 147 
 148     /**
 149      * Try handle pending {@link Reference} if there is one.<p>
 150      * Return {@code true} as a hint that there might be another
 151      * {@link Reference} pending or {@code false} when there are no more pending
 152      * {@link Reference}s at the moment and the program can do some other
 153      * useful work instead of looping.
 154      *
 155      * @param waitForNotify if {@code true} and there was no pending
 156      *                      {@link Reference}, wait until notified from VM
 157      *                      or interrupted; if {@code false}, return immediately
 158      *                      when there is no pending {@link Reference}.
 159      * @return {@code true} if there was a {@link Reference} pending and it
 160      *         was processed, or we waited for notification and either got it
 161      *         or thread was interrupted before being notified;
 162      *         {@code false} otherwise.
 163      */
 164     static boolean tryHandlePending(boolean waitForNotify) {
 165         if (!waitForNotify) {
 166             // FIXME! Calls from non-blocking helper threads not yet supported.
 167             return false;






























 168         }
 169 
 170         // Get pending references from the VM
 171         Reference<Object> pending_list = getReferencePendingList();
 172 
 173         // Enqueue references
 174         while (pending_list != null) {
 175             // Unlink
 176             Reference<Object> r = pending_list;
 177             pending_list = r.discovered;
 178             r.discovered = null;
 179 
 180             // Fast path for cleaners
 181             if (r instanceof Cleaner) {
 182                 try {
 183                     ((Cleaner)r).clean();
 184                 } catch (Throwable x) {
 185                     // Ignored
 186                 }
 187 
 188                 // Don't enqueue
 189                 continue;
 190             }
 191 
 192             // Enqueue
 193             ReferenceQueue<? super Object> q = r.queue;
 194             if (q != ReferenceQueue.NULL) {
 195                 q.enqueue(r);
 196             }
 197         }
 198 
 199         return true;
 200     }
 201 
 202     static {
 203         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 204         for (ThreadGroup tgn = tg;
 205              tgn != null;
 206              tg = tgn, tgn = tg.getParent());
 207         Thread handler = new ReferenceHandler(tg, "Reference Handler");
 208         /* If there were a special system-only priority greater than
 209          * MAX_PRIORITY, it would be used here
 210          */
 211         handler.setPriority(Thread.MAX_PRIORITY);
 212         handler.setDaemon(true);
 213         handler.start();
 214 
 215         // provide access in SharedSecrets
 216         SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
 217             @Override
 218             public boolean tryHandlePendingReference() {


< prev index next >