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

Print this page




  79      * to determine whether a Reference instance requires special treatment: If
  80      * the next field is null then the instance is active; if it is non-null,
  81      * then the collector should treat the instance normally.
  82      *
  83      * To ensure that a concurrent collector can discover active Reference
  84      * objects without interfering with application threads that may apply
  85      * the enqueue() method to those objects, collectors should link
  86      * discovered objects through the discovered field. The discovered
  87      * field is also used for linking Reference objects in the pending list.
  88      */
  89 
  90     private T referent;         /* Treated specially by GC */
  91 
  92     volatile ReferenceQueue<? super T> queue;
  93 
  94     /* When active:   NULL
  95      *     pending:   this
  96      *    Enqueued:   next reference in queue (or this if last)
  97      *    Inactive:   this
  98      */

  99     Reference next;
 100 
 101     /* When active:   next element in a discovered reference list maintained by GC (or this if last)
 102      *     pending:   next element in the pending list (or null if last)
 103      *   otherwise:   NULL
 104      */
 105     transient private Reference<T> discovered;  /* used by VM */
 106 
 107 
 108     /* Object used to synchronize with the garbage collector.  The collector
 109      * must acquire this lock at the beginning of each collection cycle.  It is
 110      * therefore critical that any code holding this lock complete as quickly
 111      * as possible, allocate no new objects, and avoid calling user code.
 112      */
 113     static private class Lock { };
 114     private static Lock lock = new Lock();
 115 
 116 
 117     /* List of References waiting to be enqueued.  The collector adds
 118      * References to this list, while the Reference-handler thread removes
 119      * them.  This list is protected by the above lock object. The
 120      * list uses the discovered field to link its elements.
 121      */
 122     private static Reference pending = null;
 123 
 124     /* High-priority thread to enqueue pending References
 125      */
 126     private static class ReferenceHandler extends Thread {
 127 
 128         ReferenceHandler(ThreadGroup g, String name) {
 129             super(g, name);
 130         }
 131 
 132         public void run() {
 133             for (;;) {
 134                 Reference r;
 135                 synchronized (lock) {
 136                     if (pending != null) {
 137                         r = pending;
 138                         pending = r.discovered;
 139                         r.discovered = null;
 140                     } else {
 141                         // The waiting on the lock may cause an OOME because it may try to allocate
 142                         // exception objects, so also catch OOME here to avoid silent exit of the
 143                         // reference handler thread.
 144                         //
 145                         // Explicitly define the order of the two exceptions we catch here
 146                         // when waiting for the lock.
 147                         //
 148                         // We do not want to try to potentially load the InterruptedException class
 149                         // (which would be done if this was its first use, and InterruptedException
 150                         // were checked first) in this situation.
 151                         //
 152                         // This may lead to the VM not ever trying to load the InterruptedException
 153                         // class again.
 154                         try {
 155                             try {
 156                                 lock.wait();
 157                             } catch (OutOfMemoryError x) { }
 158                         } catch (InterruptedException x) { }
 159                         continue;
 160                     }
 161                 }
 162 
 163                 // Fast path for cleaners
 164                 if (r instanceof Cleaner) {
 165                     ((Cleaner)r).clean();
 166                     continue;
 167                 }
 168 
 169                 ReferenceQueue q = r.queue;
 170                 if (q != ReferenceQueue.NULL) q.enqueue(r);
 171             }
 172         }
 173     }
 174 
 175     static {
 176         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 177         for (ThreadGroup tgn = tg;
 178              tgn != null;
 179              tg = tgn, tgn = tg.getParent());
 180         Thread handler = new ReferenceHandler(tg, "Reference Handler");
 181         /* If there were a special system-only priority greater than
 182          * MAX_PRIORITY, it would be used here
 183          */
 184         handler.setPriority(Thread.MAX_PRIORITY);
 185         handler.setDaemon(true);
 186         handler.start();
 187     }
 188 
 189 




  79      * to determine whether a Reference instance requires special treatment: If
  80      * the next field is null then the instance is active; if it is non-null,
  81      * then the collector should treat the instance normally.
  82      *
  83      * To ensure that a concurrent collector can discover active Reference
  84      * objects without interfering with application threads that may apply
  85      * the enqueue() method to those objects, collectors should link
  86      * discovered objects through the discovered field. The discovered
  87      * field is also used for linking Reference objects in the pending list.
  88      */
  89 
  90     private T referent;         /* Treated specially by GC */
  91 
  92     volatile ReferenceQueue<? super T> queue;
  93 
  94     /* When active:   NULL
  95      *     pending:   this
  96      *    Enqueued:   next reference in queue (or this if last)
  97      *    Inactive:   this
  98      */
  99     @SuppressWarnings("rawtypes")
 100     Reference next;
 101 
 102     /* When active:   next element in a discovered reference list maintained by GC (or this if last)
 103      *     pending:   next element in the pending list (or null if last)
 104      *   otherwise:   NULL
 105      */
 106     transient private Reference<T> discovered;  /* used by VM */
 107 
 108 
 109     /* Object used to synchronize with the garbage collector.  The collector
 110      * must acquire this lock at the beginning of each collection cycle.  It is
 111      * therefore critical that any code holding this lock complete as quickly
 112      * as possible, allocate no new objects, and avoid calling user code.
 113      */
 114     static private class Lock { };
 115     private static Lock lock = new Lock();
 116 
 117 
 118     /* List of References waiting to be enqueued.  The collector adds
 119      * References to this list, while the Reference-handler thread removes
 120      * them.  This list is protected by the above lock object. The
 121      * list uses the discovered field to link its elements.
 122      */
 123     private static Reference<Object> pending = null;
 124 
 125     /* High-priority thread to enqueue pending References
 126      */
 127     private static class ReferenceHandler extends Thread {
 128 
 129         ReferenceHandler(ThreadGroup g, String name) {
 130             super(g, name);
 131         }
 132 
 133         public void run() {
 134             for (;;) {
 135                 Reference<Object> r;
 136                 synchronized (lock) {
 137                     if (pending != null) {
 138                         r = pending;
 139                         pending = r.discovered;
 140                         r.discovered = null;
 141                     } else {
 142                         // The waiting on the lock may cause an OOME because it may try to allocate
 143                         // exception objects, so also catch OOME here to avoid silent exit of the
 144                         // reference handler thread.
 145                         //
 146                         // Explicitly define the order of the two exceptions we catch here
 147                         // when waiting for the lock.
 148                         //
 149                         // We do not want to try to potentially load the InterruptedException class
 150                         // (which would be done if this was its first use, and InterruptedException
 151                         // were checked first) in this situation.
 152                         //
 153                         // This may lead to the VM not ever trying to load the InterruptedException
 154                         // class again.
 155                         try {
 156                             try {
 157                                 lock.wait();
 158                             } catch (OutOfMemoryError x) { }
 159                         } catch (InterruptedException x) { }
 160                         continue;
 161                     }
 162                 }
 163 
 164                 // Fast path for cleaners
 165                 if (r instanceof Cleaner) {
 166                     ((Cleaner)r).clean();
 167                     continue;
 168                 }
 169 
 170                 ReferenceQueue<Object> q = r.queue;
 171                 if (q != ReferenceQueue.NULL) q.enqueue(r);
 172             }
 173         }
 174     }
 175 
 176     static {
 177         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 178         for (ThreadGroup tgn = tg;
 179              tgn != null;
 180              tg = tgn, tgn = tg.getParent());
 181         Thread handler = new ReferenceHandler(tg, "Reference Handler");
 182         /* If there were a special system-only priority greater than
 183          * MAX_PRIORITY, it would be used here
 184          */
 185         handler.setPriority(Thread.MAX_PRIORITY);
 186         handler.setDaemon(true);
 187         handler.start();
 188     }
 189 
 190