• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
ReferenceQueue()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")
poll()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      */
remove()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      */
remove(long timeoutMillis)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      * @return boolean true if reference is enqueued. false if reference failed
135      *         to enqueue.
136      */
enqueue(Reference<? extends T> reference)137     synchronized void enqueue(Reference<? extends T> reference) {
138         if (head == null) {
139             reference.queueNext = reference;
140         } else {
141             reference.queueNext = head;
142         }
143         head = reference;
144         notify();
145     }
146 
147     /** @hide */
148     public static Reference unenqueued = null;
149 
add(Reference<?> list)150     static void add(Reference<?> list) {
151         synchronized (ReferenceQueue.class) {
152             if (unenqueued == null) {
153                 unenqueued = list;
154             } else {
155                 Reference<?> next = unenqueued.pendingNext;
156                 unenqueued.pendingNext = list.pendingNext;
157                 list.pendingNext = next;
158             }
159             ReferenceQueue.class.notifyAll();
160         }
161     }
162 }
163