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

Print this page




   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.ref;
  27 
  28 import sun.misc.Cleaner;


  29 
  30 /**
  31  * Abstract base class for reference objects.  This class defines the
  32  * operations common to all reference objects.  Because reference objects are
  33  * implemented in close cooperation with the garbage collector, this class may
  34  * not be subclassed directly.
  35  *
  36  * @author   Mark Reinhold
  37  * @since    1.2
  38  */
  39 
  40 public abstract class Reference<T> {
  41 
  42     /* A Reference instance is in one of four possible internal states:
  43      *
  44      *     Active: Subject to special treatment by the garbage collector.  Some
  45      *     time after the collector detects that the reachability of the
  46      *     referent has changed to the appropriate state, it changes the
  47      *     instance's state to either Pending or Inactive, depending upon
  48      *     whether or not the instance was registered with a queue when it was


 130             try {
 131                 Class.forName(clazz.getName(), true, clazz.getClassLoader());
 132             } catch (ClassNotFoundException e) {
 133                 throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
 134             }
 135         }
 136 
 137         static {
 138             // pre-load and initialize InterruptedException and Cleaner classes
 139             // so that we don't get into trouble later in the run loop if there's
 140             // memory shortage while loading/initializing them lazily.
 141             ensureClassInitialized(InterruptedException.class);
 142             ensureClassInitialized(Cleaner.class);
 143         }
 144 
 145         ReferenceHandler(ThreadGroup g, String name) {
 146             super(g, name);
 147         }
 148 
 149         public void run() {
 150             for (;;) {






















 151                 Reference<Object> r;
 152                 Cleaner c;
 153                 try {
 154                     synchronized (lock) {
 155                         if (pending != null) {
 156                             r = pending;
 157                             // 'instanceof' might throw OutOfMemoryError sometimes
 158                             // so do this before un-linking 'r' from the 'pending' chain...
 159                             c = r instanceof Cleaner ? (Cleaner) r : null;
 160                             // unlink 'r' from 'pending' chain
 161                             pending = r.discovered;
 162                             r.discovered = null;
 163                         } else {
 164                             // The waiting on the lock may cause an OutOfMemoryError
 165                             // because it may try to allocate exception objects.

 166                             lock.wait();
 167                             continue;


 168                         }
 169                     }
 170                 } catch (OutOfMemoryError x) {
 171                     // Give other threads CPU time so they hopefully drop some live references
 172                     // and GC reclaims some space.
 173                     // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
 174                     // persistently throws OOME for some time...
 175                     Thread.yield();
 176                     // retry
 177                     continue;
 178                 } catch (InterruptedException x) {
 179                     // retry
 180                     continue;
 181                 }
 182 
 183                 // Fast path for cleaners
 184                 if (c != null) {
 185                     c.clean();
 186                     continue;
 187                 }
 188 
 189                 ReferenceQueue<Object> q = r.queue;
 190                 if (q != ReferenceQueue.NULL) q.enqueue(r);
 191             }
 192         }
 193     }
 194 
 195     static {
 196         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 197         for (ThreadGroup tgn = tg;
 198              tgn != null;
 199              tg = tgn, tgn = tg.getParent());
 200         Thread handler = new ReferenceHandler(tg, "Reference Handler");
 201         /* If there were a special system-only priority greater than
 202          * MAX_PRIORITY, it would be used here
 203          */
 204         handler.setPriority(Thread.MAX_PRIORITY);
 205         handler.setDaemon(true);
 206         handler.start();
 207     }
 208 








 209 
 210     /* -- Referent accessor and setters -- */
 211 
 212     /**
 213      * Returns this reference object's referent.  If this reference object has
 214      * been cleared, either by the program or by the garbage collector, then
 215      * this method returns <code>null</code>.
 216      *
 217      * @return   The object to which this reference refers, or
 218      *           <code>null</code> if this reference object has been cleared
 219      */
 220     public T get() {
 221         return this.referent;
 222     }
 223 
 224     /**
 225      * Clears this reference object.  Invoking this method will not cause this
 226      * object to be enqueued.
 227      *
 228      * <p> This method is invoked only by Java code; when the garbage collector




   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.ref;
  27 
  28 import sun.misc.Cleaner;
  29 import sun.misc.JavaLangRefAccess;
  30 import sun.misc.SharedSecrets;
  31 
  32 /**
  33  * Abstract base class for reference objects.  This class defines the
  34  * operations common to all reference objects.  Because reference objects are
  35  * implemented in close cooperation with the garbage collector, this class may
  36  * not be subclassed directly.
  37  *
  38  * @author   Mark Reinhold
  39  * @since    1.2
  40  */
  41 
  42 public abstract class Reference<T> {
  43 
  44     /* A Reference instance is in one of four possible internal states:
  45      *
  46      *     Active: Subject to special treatment by the garbage collector.  Some
  47      *     time after the collector detects that the reachability of the
  48      *     referent has changed to the appropriate state, it changes the
  49      *     instance's state to either Pending or Inactive, depending upon
  50      *     whether or not the instance was registered with a queue when it was


 132             try {
 133                 Class.forName(clazz.getName(), true, clazz.getClassLoader());
 134             } catch (ClassNotFoundException e) {
 135                 throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
 136             }
 137         }
 138 
 139         static {
 140             // pre-load and initialize InterruptedException and Cleaner classes
 141             // so that we don't get into trouble later in the run loop if there's
 142             // memory shortage while loading/initializing them lazily.
 143             ensureClassInitialized(InterruptedException.class);
 144             ensureClassInitialized(Cleaner.class);
 145         }
 146 
 147         ReferenceHandler(ThreadGroup g, String name) {
 148             super(g, name);
 149         }
 150 
 151         public void run() {
 152             while (true) {
 153                 tryHandlePending(true);
 154             }
 155         }
 156     }
 157 
 158     /**
 159      * Try handle pending {@link Reference} if there is one.<p>
 160      * Return {@code true} as a hint that there might be another
 161      * {@link Reference} pending or {@code false} when there are no more pending
 162      * {@link Reference}s at the moment and the program can do some other
 163      * useful work instead of looping.
 164      *
 165      * @param waitForNotify if {@code true} and there was no pending
 166      *                      {@link Reference}, wait until notified from VM
 167      *                      or interrupted; if {@code false}, return immediately
 168      *                      when there is no pending {@link Reference}.
 169      * @return {@code true} if there was a {@link Reference} pending and it
 170      *         was processed, or we waited for notification and either got it
 171      *         or thread was interrupted before being notified;
 172      *         {@code false} otherwise.
 173      */
 174     static boolean tryHandlePending(boolean waitForNotify) {
 175         Reference<Object> r;
 176         Cleaner c;
 177         try {
 178             synchronized (lock) {
 179                 if (pending != null) {
 180                     r = pending;
 181                     // 'instanceof' might throw OutOfMemoryError sometimes
 182                     // so do this before un-linking 'r' from the 'pending' chain...
 183                     c = r instanceof Cleaner ? (Cleaner) r : null;
 184                     // unlink 'r' from 'pending' chain
 185                     pending = r.discovered;
 186                     r.discovered = null;
 187                 } else {
 188                     // The waiting on the lock may cause an OutOfMemoryError
 189                     // because it may try to allocate exception objects.
 190                     if (waitForNotify) {
 191                         lock.wait();
 192                     }
 193                     // retry if waited
 194                     return waitForNotify;
 195                 }
 196             }
 197         } catch (OutOfMemoryError x) {
 198             // Give other threads CPU time so they hopefully drop some live references
 199             // and GC reclaims some space.
 200             // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
 201             // persistently throws OOME for some time...
 202             Thread.yield();
 203             // retry
 204             return true;
 205         } catch (InterruptedException x) {
 206             // retry
 207             return true;
 208         }
 209 
 210         // Fast path for cleaners
 211         if (c != null) {
 212             c.clean();
 213             return true;
 214         }
 215 
 216         ReferenceQueue<? super Object> q = r.queue;
 217         if (q != ReferenceQueue.NULL) q.enqueue(r);
 218         return true;

 219     }
 220 
 221     static {
 222         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 223         for (ThreadGroup tgn = tg;
 224              tgn != null;
 225              tg = tgn, tgn = tg.getParent());
 226         Thread handler = new ReferenceHandler(tg, "Reference Handler");
 227         /* If there were a special system-only priority greater than
 228          * MAX_PRIORITY, it would be used here
 229          */
 230         handler.setPriority(Thread.MAX_PRIORITY);
 231         handler.setDaemon(true);
 232         handler.start();

 233 
 234         // provide access in SharedSecrets
 235         SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
 236             @Override
 237             public boolean tryHandlePendingReference() {
 238                 return tryHandlePending(false);
 239             }
 240         });
 241     }
 242 
 243     /* -- Referent accessor and setters -- */
 244 
 245     /**
 246      * Returns this reference object's referent.  If this reference object has
 247      * been cleared, either by the program or by the garbage collector, then
 248      * this method returns <code>null</code>.
 249      *
 250      * @return   The object to which this reference refers, or
 251      *           <code>null</code> if this reference object has been cleared
 252      */
 253     public T get() {
 254         return this.referent;
 255     }
 256 
 257     /**
 258      * Clears this reference object.  Invoking this method will not cause this
 259      * object to be enqueued.
 260      *
 261      * <p> This method is invoked only by Java code; when the garbage collector