forked from kangjianwei/LearningJDK
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReferenceQueue.java
216 lines (197 loc) · 8.08 KB
/
ReferenceQueue.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.ref;
import jdk.internal.misc.VM;
import java.util.function.Consumer;
/**
* Reference queues, to which registered reference objects are appended by the
* garbage collector after the appropriate reachability changes are detected.
*
* @author Mark Reinhold
* @since 1.2
*/
// 存储GC之后报废的Reference(该引用指向的对象被回收),配合Reference类完成一些清理操作
public class ReferenceQueue<T> {
static final ReferenceQueue<Object> NULL = new Null(); // 此处代表Reference没有关联的ReferenceQueue,无法入队
static final ReferenceQueue<Object> ENQUEUED = new Null(); // 此处代表Reference已经在队列中,无法再入队
private final Lock lock = new Lock();
private volatile Reference<? extends T> head;
private long queueLength = 0;
/**
* Constructs a new reference-object queue.
*/
public ReferenceQueue() {
}
/**
* Polls this queue to see if a reference object is available.
* If one is available without further delay then it is removed from the queue and returned.
* Otherwise this method immediately returns {@code null}.
*
* @return A reference object, if one was immediately available, otherwise {@code null}
*/
// 从ReferenceQueue中删除一个Reference并将其返回
public Reference<? extends T> poll() {
if(head == null) {
return null;
}
synchronized(lock) {
return reallyPoll();
}
}
// 将“报废引用”入队
boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
synchronized(lock) {
// Check that since getting the lock this reference hasn't already been enqueued (and even then removed)
ReferenceQueue<?> queue = r.queue;
if((queue == NULL) || (queue == ENQUEUED)) {
return false;
}
assert queue == this;
// Self-loop end, so if a FinalReference it remains inactive.
r.next = (head == null) ? r : head;
head = r;
queueLength++;
// Update r.queue *after* adding to list, to avoid race with concurrent enqueued checks and fast-path poll().
// Volatiles ensure ordering.
r.queue = ENQUEUED;
if(r instanceof FinalReference) {
VM.addFinalRefCount(1);
}
lock.notifyAll();
return true;
}
}
/**
* Removes the next reference object in this queue, blocking until one
* becomes available.
*
* @return A reference object, blocking until one becomes available
*
* @throws InterruptedException If the wait is interrupted
*/
// 从ReferenceQueue中删除并返回一个Reference(如果没有就陷入阻塞,直到队列里有引用就取出)
public Reference<? extends T> remove() throws InterruptedException {
return remove(0);
}
/**
* Removes the next reference object in this queue, blocking until either
* one becomes available or the given timeout period expires.
*
* <p> This method does not offer real-time guarantees: It schedules the
* timeout as if by invoking the {@link Object#wait(long)} method.
*
* @param timeout If positive, block for up to {@code timeout}
* milliseconds while waiting for a reference to be
* added to this queue. If zero, block indefinitely.
*
* @return A reference object, if one was available within the specified
* timeout period, otherwise {@code null}
*
* @throws IllegalArgumentException If the value of the timeout argument is negative
* @throws InterruptedException If the timeout wait is interrupted
*/
// 轮询,在指定时间内,直到找到一个非空的Reference才返回
public Reference<? extends T> remove(long timeout) throws IllegalArgumentException, InterruptedException {
if(timeout < 0) {
throw new IllegalArgumentException("Negative timeout value");
}
synchronized(lock) {
Reference<? extends T> r = reallyPoll();
if(r != null)
return r;
long start = (timeout == 0) ? 0 : System.nanoTime();
for(; ; ) {
lock.wait(timeout);
r = reallyPoll();
if(r != null)
return r;
if(timeout != 0) {
long end = System.nanoTime();
timeout -= (end - start) / 1000_000;
if(timeout <= 0)
return null;
start = end;
}
}
}
}
// 从ReferenceQueue中删除一个Reference并将其返回
private Reference<? extends T> reallyPoll() { /* Must hold lock */
Reference<? extends T> r = head;
if(r != null) {
r.queue = NULL;
// Update r.queue *before* removing from list, to avoid race with concurrent enqueued checks and fast-path poll().
// Volatiles ensure ordering.
@SuppressWarnings("unchecked")
Reference<? extends T> rn = r.next;
// Handle self-looped next as end of list designator.
head = (rn == r) ? null : rn;
// Self-loop next rather than setting to null, so if a
// FinalReference it remains inactive.
r.next = r;
queueLength--;
if(r instanceof FinalReference) {
VM.addFinalRefCount(-1);
}
return r;
}
return null;
}
/**
* Iterate queue and invoke given action with each Reference.
* Suitable for diagnostic purposes.
* WARNING: any use of this method should make sure to not
* retain the referents of iterated references (in case of
* FinalReference(s)) so that their life is not prolonged more
* than necessary.
*/
void forEach(Consumer<? super Reference<? extends T>> action) {
for(Reference<? extends T> r = head; r != null; ) {
action.accept(r);
@SuppressWarnings("unchecked")
Reference<? extends T> rn = r.next;
if(rn == r) {
if(r.queue == ENQUEUED) {
// still enqueued -> we reached end of chain
r = null;
} else {
// already dequeued: r.queue == NULL; ->
// restart from head when overtaken by queue poller(s)
r = head;
}
} else {
// next in chain
r = rn;
}
}
}
private static class Null extends ReferenceQueue<Object> {
boolean enqueue(Reference<?> r) {
return false;
}
}
private static class Lock {
}
}