1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.lang.ref; 19 20 /** 21 * The {@code ReferenceQueue} is the container on which reference objects are 22 * enqueued when the garbage collector detects the reachability type specified 23 * for the referent. 24 * 25 * @since 1.2 26 */ 27 public class ReferenceQueue<T> { 28 private static final int NANOS_PER_MILLI = 1000000; 29 30 private Reference<? extends T> head; 31 32 /** 33 * Constructs a new instance of this class. 34 */ 35 public ReferenceQueue() { 36 } 37 38 /** 39 * Returns the next available reference from the queue, removing it in the 40 * process. Does not wait for a reference to become available. 41 * 42 * @return the next available reference, or {@code null} if no reference is 43 * immediately available 44 */ 45 @SuppressWarnings("unchecked") 46 public synchronized Reference<? extends T> poll() { 47 if (head == null) { 48 return null; 49 } 50 51 Reference<? extends T> ret; 52 53 ret = head; 54 55 if (head == head.queueNext) { 56 head = null; 57 } else { 58 head = head.queueNext; 59 } 60 61 ret.queueNext = null; 62 63 return ret; 64 } 65 66 /** 67 * Returns the next available reference from the queue, removing it in the 68 * process. Waits indefinitely for a reference to become available. 69 * 70 * @throws InterruptedException if the blocking call was interrupted 71 */ 72 public Reference<? extends T> remove() throws InterruptedException { 73 return remove(0L); 74 } 75 76 /** 77 * Returns the next available reference from the queue, removing it in the 78 * process. Waits for a reference to become available or the given timeout 79 * period to elapse, whichever happens first. 80 * 81 * @param timeoutMillis maximum time to spend waiting for a reference object 82 * to become available. A value of {@code 0} results in the method 83 * waiting indefinitely. 84 * @return the next available reference, or {@code null} if no reference 85 * becomes available within the timeout period 86 * @throws IllegalArgumentException if {@code timeoutMillis < 0}. 87 * @throws InterruptedException if the blocking call was interrupted 88 */ 89 public synchronized Reference<? extends T> remove(long timeoutMillis) 90 throws InterruptedException { 91 if (timeoutMillis < 0) { 92 throw new IllegalArgumentException("timeout < 0: " + timeoutMillis); 93 } 94 95 if (head != null) { 96 return poll(); 97 } 98 99 // avoid overflow: if total > 292 years, just wait forever 100 if (timeoutMillis == 0 || (timeoutMillis > Long.MAX_VALUE / NANOS_PER_MILLI)) { 101 do { 102 wait(0); 103 } while (head == null); 104 return poll(); 105 } 106 107 // guaranteed to not overflow 108 long nanosToWait = timeoutMillis * NANOS_PER_MILLI; 109 int timeoutNanos = 0; 110 111 // wait until notified or the timeout has elapsed 112 long startTime = System.nanoTime(); 113 while (true) { 114 wait(timeoutMillis, timeoutNanos); 115 if (head != null) { 116 break; 117 } 118 long nanosElapsed = System.nanoTime() - startTime; 119 long nanosRemaining = nanosToWait - nanosElapsed; 120 if (nanosRemaining <= 0) { 121 break; 122 } 123 timeoutMillis = nanosRemaining / NANOS_PER_MILLI; 124 timeoutNanos = (int) (nanosRemaining - timeoutMillis * NANOS_PER_MILLI); 125 } 126 return poll(); 127 } 128 129 /** 130 * Enqueue the reference object on the receiver. 131 * 132 * @param reference 133 * reference object to be enqueued. 134 */ 135 synchronized void enqueue(Reference<? extends T> reference) { 136 if (head == null) { 137 reference.queueNext = reference; 138 } else { 139 reference.queueNext = head; 140 } 141 head = reference; 142 notify(); 143 } 144 145 /** @hide */ 146 public static Reference<?> unenqueued = null; 147 148 static void add(Reference<?> list) { 149 synchronized (ReferenceQueue.class) { 150 if (unenqueued == null) { 151 unenqueued = list; 152 } else { 153 Reference<?> next = unenqueued.pendingNext; 154 unenqueued.pendingNext = list.pendingNext; 155 list.pendingNext = next; 156 } 157 ReferenceQueue.class.notifyAll(); 158 } 159 } 160 } 161