Reference.java revision 12745:f068a4ffddd2
1/* 2 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 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 26package java.lang.ref; 27 28import sun.misc.Cleaner; 29import sun.misc.JavaLangRefAccess; 30import sun.misc.ManagedLocalsThread; 31import sun.misc.SharedSecrets; 32import jdk.internal.HotSpotIntrinsicCandidate; 33 34/** 35 * Abstract base class for reference objects. This class defines the 36 * operations common to all reference objects. Because reference objects are 37 * implemented in close cooperation with the garbage collector, this class may 38 * not be subclassed directly. 39 * 40 * @author Mark Reinhold 41 * @since 1.2 42 */ 43 44public abstract class Reference<T> { 45 46 /* A Reference instance is in one of four possible internal states: 47 * 48 * Active: Subject to special treatment by the garbage collector. Some 49 * time after the collector detects that the reachability of the 50 * referent has changed to the appropriate state, it changes the 51 * instance's state to either Pending or Inactive, depending upon 52 * whether or not the instance was registered with a queue when it was 53 * created. In the former case it also adds the instance to the 54 * pending-Reference list. Newly-created instances are Active. 55 * 56 * Pending: An element of the pending-Reference list, waiting to be 57 * enqueued by the Reference-handler thread. Unregistered instances 58 * are never in this state. 59 * 60 * Enqueued: An element of the queue with which the instance was 61 * registered when it was created. When an instance is removed from 62 * its ReferenceQueue, it is made Inactive. Unregistered instances are 63 * never in this state. 64 * 65 * Inactive: Nothing more to do. Once an instance becomes Inactive its 66 * state will never change again. 67 * 68 * The state is encoded in the queue and next fields as follows: 69 * 70 * Active: queue = ReferenceQueue with which instance is registered, or 71 * ReferenceQueue.NULL if it was not registered with a queue; next = 72 * null. 73 * 74 * Pending: queue = ReferenceQueue with which instance is registered; 75 * next = this 76 * 77 * Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance 78 * in queue, or this if at end of list. 79 * 80 * Inactive: queue = ReferenceQueue.NULL; next = this. 81 * 82 * With this scheme the collector need only examine the next field in order 83 * to determine whether a Reference instance requires special treatment: If 84 * the next field is null then the instance is active; if it is non-null, 85 * then the collector should treat the instance normally. 86 * 87 * To ensure that a concurrent collector can discover active Reference 88 * objects without interfering with application threads that may apply 89 * the enqueue() method to those objects, collectors should link 90 * discovered objects through the discovered field. The discovered 91 * field is also used for linking Reference objects in the pending list. 92 */ 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 ManagedLocalsThread { 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, name); 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() { 240 return tryHandlePending(false); 241 } 242 }); 243 } 244 245 /* -- Referent accessor and setters -- */ 246 247 /** 248 * Returns this reference object's referent. If this reference object has 249 * been cleared, either by the program or by the garbage collector, then 250 * this method returns <code>null</code>. 251 * 252 * @return The object to which this reference refers, or 253 * <code>null</code> if this reference object has been cleared 254 */ 255 @HotSpotIntrinsicCandidate 256 public T get() { 257 return this.referent; 258 } 259 260 /** 261 * Clears this reference object. Invoking this method will not cause this 262 * object to be enqueued. 263 * 264 * <p> This method is invoked only by Java code; when the garbage collector 265 * clears references it does so directly, without invoking this method. 266 */ 267 public void clear() { 268 this.referent = null; 269 } 270 271 272 /* -- Queue operations -- */ 273 274 /** 275 * Tells whether or not this reference object has been enqueued, either by 276 * the program or by the garbage collector. If this reference object was 277 * not registered with a queue when it was created, then this method will 278 * always return <code>false</code>. 279 * 280 * @return <code>true</code> if and only if this reference object has 281 * been enqueued 282 */ 283 public boolean isEnqueued() { 284 return (this.queue == ReferenceQueue.ENQUEUED); 285 } 286 287 /** 288 * Adds this reference object to the queue with which it is registered, 289 * if any. 290 * 291 * <p> This method is invoked only by Java code; when the garbage collector 292 * enqueues references it does so directly, without invoking this method. 293 * 294 * @return <code>true</code> if this reference object was successfully 295 * enqueued; <code>false</code> if it was already enqueued or if 296 * it was not registered with a queue when it was created 297 */ 298 public boolean enqueue() { 299 return this.queue.enqueue(this); 300 } 301 302 303 /* -- Constructors -- */ 304 305 Reference(T referent) { 306 this(referent, null); 307 } 308 309 Reference(T referent, ReferenceQueue<? super T> queue) { 310 this.referent = referent; 311 this.queue = (queue == null) ? ReferenceQueue.NULL : queue; 312 } 313 314} 315