1 /* 2 * Copyright (c) 1997, 2025, 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 java.util.function.Consumer; 29 import jdk.internal.misc.VM; 30 import jdk.internal.vm.Continuation; 31 import jdk.internal.vm.ContinuationSupport; 32 33 /** 34 * Reference queues, to which registered reference objects are appended by the 35 * garbage collector after the appropriate reachability changes are detected. 36 * 37 * <p>{@linkplain java.lang.ref##MemoryConsistency Memory consistency effects}: 38 * The enqueueing of a reference to a queue (by the garbage collector, or by a 39 * successful call to {@link Reference#enqueue}) 40 * <a href="{@docRoot}/java.base/java/util/concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a> 41 * the reference is removed from the queue by {@link ReferenceQueue#poll} or 42 * {@link ReferenceQueue#remove}. 43 * 44 * @param <T> the type of the reference object 45 * 46 * @author Mark Reinhold 47 * @since 1.2 48 */ 49 50 public class ReferenceQueue<T> { 51 private static class Null extends ReferenceQueue<Object> { 52 @Override 53 boolean enqueue(Reference<?> r) { 54 return false; 55 } 56 } 57 58 static final ReferenceQueue<Object> NULL = new Null(); 59 static final ReferenceQueue<Object> ENQUEUED = new Null(); 60 61 private volatile Reference<? extends T> head; 62 private long queueLength = 0; 63 64 private static class Lock { }; 65 private final Lock lock = new Lock(); 66 67 /** 68 * Constructs a new reference-object queue. 69 */ 70 public ReferenceQueue() { 71 } 72 73 private boolean enqueue0(Reference<? extends T> r) { // must hold lock 74 // Check that since getting the lock this reference hasn't already been 75 // enqueued (and even then removed) 76 ReferenceQueue<?> queue = r.queue; 77 if ((queue == NULL) || (queue == ENQUEUED)) { 78 return false; 79 } 80 assert queue == this; 81 // Self-loop end, so if a FinalReference it remains inactive. 82 r.next = (head == null) ? r : head; 83 head = r; 84 queueLength++; 85 // Update r.queue *after* adding to list, to avoid race 86 // with concurrent enqueued checks and fast-path poll(). 87 // Volatiles ensure ordering. 88 r.queue = ENQUEUED; 89 if (r instanceof FinalReference) { 90 VM.addFinalRefCount(1); 91 } 92 lock.notifyAll(); 93 return true; 94 } 95 96 private Reference<? extends T> poll0() { // must hold lock 97 Reference<? extends T> r = head; 98 if (r != null) { 99 r.queue = NULL; 100 // Update r.queue *before* removing from list, to avoid 101 // race with concurrent enqueued checks and fast-path 102 // poll(). Volatiles ensure ordering. 103 @SuppressWarnings("unchecked") 104 Reference<? extends T> rn = r.next; 105 // Handle self-looped next as end of list designator. 106 head = (rn == r) ? null : rn; 107 // Self-loop next rather than setting to null, so if a 108 // FinalReference it remains inactive. 109 r.next = r; 110 queueLength--; 111 if (r instanceof FinalReference) { 112 VM.addFinalRefCount(-1); 113 } 114 return r; 115 } 116 return null; 117 } 118 119 private Reference<? extends T> remove0(long timeout) throws InterruptedException { // must hold lock 120 Reference<? extends T> r = poll0(); 121 if (r != null) return r; 122 long start = System.nanoTime(); 123 for (;;) { 124 lock.wait(timeout); 125 r = poll0(); 126 if (r != null) return r; 127 long end = System.nanoTime(); 128 timeout -= (end - start) / 1000_000; 129 if (timeout <= 0) return null; 130 start = end; 131 } 132 } 133 134 private Reference<? extends T> remove0() throws InterruptedException { // must hold lock 135 for (;;) { 136 var r = poll0(); 137 if (r != null) return r; 138 lock.wait(); 139 } 140 } 141 142 boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */ 143 synchronized (lock) { 144 return enqueue0(r); 145 } 146 } 147 148 /** 149 * Polls this queue to see if a reference object is available. If one is 150 * available without further delay then it is removed from the queue and 151 * returned. Otherwise this method immediately returns {@code null}. 152 * 153 * @return A reference object, if one was immediately available, 154 * otherwise {@code null} 155 * @see java.lang.ref.Reference#enqueue() 156 */ 157 public Reference<? extends T> poll() { 158 if (head == null) 159 return null; 160 161 // Prevent a virtual thread from being preempted as this could potentially 162 // deadlock with a carrier that is polling the same reference queue. 163 boolean pinned = Thread.currentThread().isVirtual() && ContinuationSupport.pinIfSupported(); 164 try { 165 synchronized (lock) { 166 return poll0(); 167 } 168 } finally { 169 if (pinned) Continuation.unpin(); 170 } 171 } 172 173 /** 174 * Removes the next reference object in this queue, blocking until either 175 * one becomes available or the given timeout period expires. 176 * 177 * <p> This method does not offer real-time guarantees: It schedules the 178 * timeout as if by invoking the {@link Object#wait(long)} method. 179 * 180 * @param timeout If positive, block for up to {@code timeout} 181 * milliseconds while waiting for a reference to be 182 * added to this queue. If zero, block indefinitely. 183 * 184 * @return A reference object, if one was available within the specified 185 * timeout period, otherwise {@code null} 186 * 187 * @throws IllegalArgumentException 188 * If the value of the timeout argument is negative 189 * 190 * @throws InterruptedException 191 * If the timeout wait is interrupted 192 * 193 * @see java.lang.ref.Reference#enqueue() 194 */ 195 public Reference<? extends T> remove(long timeout) throws InterruptedException { 196 if (timeout < 0) 197 throw new IllegalArgumentException("Negative timeout value"); 198 if (timeout == 0) 199 return remove(); 200 201 synchronized (lock) { 202 return remove0(timeout); 203 } 204 } 205 206 /** 207 * Removes the next reference object in this queue, blocking until one 208 * becomes available. 209 * 210 * @return A reference object, blocking until one becomes available 211 * @throws InterruptedException If the wait is interrupted 212 * @see java.lang.ref.Reference#enqueue() 213 */ 214 public Reference<? extends T> remove() throws InterruptedException { 215 synchronized (lock) { 216 return remove0(); 217 } 218 } 219 220 /** 221 * Iterate queue and invoke given action with each Reference. 222 * Suitable for diagnostic purposes. 223 * WARNING: any use of this method should make sure to not 224 * retain the referents of iterated references (in case of 225 * FinalReference(s)) so that their life is not prolonged more 226 * than necessary. 227 */ 228 void forEach(Consumer<? super Reference<? extends T>> action) { 229 for (Reference<? extends T> r = head; r != null;) { 230 action.accept(r); 231 @SuppressWarnings("unchecked") 232 Reference<? extends T> rn = r.next; 233 if (rn == r) { 234 if (r.queue == ENQUEUED) { 235 // still enqueued -> we reached end of chain 236 r = null; 237 } else { 238 // already dequeued: r.queue == NULL; -> 239 // restart from head when overtaken by queue poller(s) 240 r = head; 241 } 242 } else { 243 // next in chain 244 r = rn; 245 } 246 } 247 } 248 }