1 /* 2 * Copyright (c) 1997, 2006, 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 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 49 * created. In the former case it also adds the instance to the 50 * pending-Reference list. Newly-created instances are Active. 51 * 52 * Pending: An element of the pending-Reference list, waiting to be 53 * enqueued by the Reference-handler thread. Unregistered instances 54 * are never in this state. 55 * 56 * Enqueued: An element of the queue with which the instance was 57 * registered when it was created. When an instance is removed from 58 * its ReferenceQueue, it is made Inactive. Unregistered instances are 59 * never in this state. 60 * 61 * Inactive: Nothing more to do. Once an instance becomes Inactive its 62 * state will never change again. 63 * 64 * The state is encoded in the queue and next fields as follows: 65 * 66 * Active: queue = ReferenceQueue with which instance is registered, or 67 * ReferenceQueue.NULL if it was not registered with a queue; next = 68 * null. 69 * 70 * Pending: queue = ReferenceQueue with which instance is registered; 71 * next = this 72 * 73 * Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance 74 * in queue, or this if at end of list. 75 * 76 * Inactive: queue = ReferenceQueue.NULL; next = this. 77 * 78 * With this scheme the collector need only examine the next field in order 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 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 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 try { 142 lock.wait(); 143 } catch (InterruptedException x) { } 144 continue; 145 } 146 } 147 148 // Fast path for cleaners 149 if (r instanceof Cleaner) { 150 ((Cleaner)r).clean(); 151 continue; 152 } 153 154 ReferenceQueue q = r.queue; 155 if (q != ReferenceQueue.NULL) q.enqueue(r); 156 } 157 } 158 } 159 160 static { 161 ThreadGroup tg = Thread.currentThread().getThreadGroup(); 162 for (ThreadGroup tgn = tg; 163 tgn != null; 164 tg = tgn, tgn = tg.getParent()); 165 Thread handler = new ReferenceHandler(tg, "Reference Handler"); 166 /* If there were a special system-only priority greater than 167 * MAX_PRIORITY, it would be used here 168 */ 169 handler.setPriority(Thread.MAX_PRIORITY); 170 handler.setDaemon(true); 171 handler.start(); 172 } 173 174 175 /* -- Referent accessor and setters -- */ 176 177 /** 178 * Returns this reference object's referent. If this reference object has 179 * been cleared, either by the program or by the garbage collector, then 180 * this method returns <code>null</code>. 181 * 182 * @return The object to which this reference refers, or 183 * <code>null</code> if this reference object has been cleared 184 */ 185 public T get() { 186 return this.referent; 187 } 188 189 /** 190 * Clears this reference object. Invoking this method will not cause this 191 * object to be enqueued. 192 * 193 * <p> This method is invoked only by Java code; when the garbage collector 194 * clears references it does so directly, without invoking this method. 195 */ 196 public void clear() { 197 this.referent = null; 198 } 199 200 201 /* -- Queue operations -- */ 202 203 /** 204 * Tells whether or not this reference object has been enqueued, either by 205 * the program or by the garbage collector. If this reference object was 206 * not registered with a queue when it was created, then this method will 207 * always return <code>false</code>. 208 * 209 * @return <code>true</code> if and only if this reference object has 210 * been enqueued 211 */ 212 public boolean isEnqueued() { 213 synchronized (this) { 214 return (this.next != null && this.queue == ReferenceQueue.ENQUEUED); 215 } 216 } 217 218 /** 219 * Adds this reference object to the queue with which it is registered, 220 * if any. 221 * 222 * <p> This method is invoked only by Java code; when the garbage collector 223 * enqueues references it does so directly, without invoking this method. 224 * 225 * @return <code>true</code> if this reference object was successfully 226 * enqueued; <code>false</code> if it was already enqueued or if 227 * it was not registered with a queue when it was created 228 */ 229 public boolean enqueue() { 230 return this.queue.enqueue(this); 231 } 232 233 234 /* -- Constructors -- */ 235 236 Reference(T referent) { 237 this(referent, null); 238 } 239 240 Reference(T referent, ReferenceQueue<? super T> queue) { 241 this.referent = referent; 242 this.queue = (queue == null) ? ReferenceQueue.NULL : queue; 243 } 244 245 }