-
Notifications
You must be signed in to change notification settings - Fork 670
/
Copy pathAbstractSelector.java
298 lines (253 loc) · 12.8 KB
/
AbstractSelector.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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/*
* Copyright (c) 2000, 2017, 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.nio.channels.spi;
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import sun.nio.ch.Interruptible;
/**
* Base implementation class for selectors.
*
* <p> This class encapsulates the low-level machinery required to implement
* the interruption of selection operations. A concrete selector class must
* invoke the {@link #begin begin} and {@link #end end} methods before and
* after, respectively, invoking an I/O operation that might block
* indefinitely. In order to ensure that the {@link #end end} method is always
* invoked, these methods should be used within a
* {@code try} ... {@code finally} block:
*
* <blockquote><pre id="be">
* try {
* begin();
* // Perform blocking I/O operation here
* ...
* } finally {
* end();
* }</pre></blockquote>
*
* <p> This class also defines methods for maintaining a selector's
* cancelled-key set and for removing a key from its channel's key set, and
* declares the abstract {@link #register register} method that is invoked by a
* selectable channel's {@link AbstractSelectableChannel#register register}
* method in order to perform the actual work of registering a channel. </p>
*
*
* @author Mark Reinhold
* @author JSR-51 Expert Group
* @since 1.4
*/
// 通道选择器的抽象实现
public abstract class AbstractSelector extends Selector {
/** The provider that created this selector */
// 构造当前选择器对象的选择器工厂
private final SelectorProvider provider;
// 标记选择器处于开启还是关闭状态
private final AtomicBoolean selectorOpen = new AtomicBoolean(true);
// 线程中断回调标记,在中断选择器主线程时会被用到
private Interruptible interruptor = null;
/*
* "已取消键临时集合"
*
* "临时"的含义是每一轮select()的前后,这里的"选择键"都会被移除
*/
private final Set<SelectionKey> cancelledKeys = new HashSet<SelectionKey>();
/*▼ 构造器 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Initializes a new instance of this class.
*
* @param provider The provider that created this selector
*/
protected AbstractSelector(SelectorProvider provider) {
this.provider = provider;
}
/*▲ 构造器 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 注册/反注册 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Registers the given channel with this selector.
*
* <p> This method is invoked by a channel's {@link
* AbstractSelectableChannel#register register} method in order to perform
* the actual work of registering the channel with this selector. </p>
*
* @param ch The channel to be registered
* @param ops The initial interest set, which must be valid
* @param att The initial attachment for the resulting key
*
* @return A new key representing the registration of the given channel
* with this selector
*/
/*
* 通道channel向当前选择器发起注册操作,返回生成的"选择键"
*
* 具体的注册行为是:
* 将通道(channel)、选择器(selector)、监听事件(ops)、附属对象(attachment)这四个属性打包成一个"选择键"对象,
* 并将该对象分别存储到各个相关的"选择键"集合/队列中,涉及到的"选择键"集合/队列包括:
*
* AbstractSelectableChannel -> keys "选择键"集合
* SelectorImpl -> keys "新注册键集合"
* WindowsSelectorImpl -> newKeys "新注册键临时队列"
* WindowsSelectorImpl -> updateKeys "已更新键临时队列"
* AbstractSelector -> cancelledKeys "已取消键临时集合"
*
* 注:需要确保当前通道为非阻塞通道
*/
protected abstract SelectionKey register(AbstractSelectableChannel channel, int ops, Object att);
/**
* Removes the given key from its channel's key set.
*
* This method must be invoked by the selector for each channel that it deregisters.
*
* @param key The selection key to be removed
*/
/*
* 从key所属通道的"选择键"集合keys中移除key,并将key标记为无效
*
* 参见AbstractSelectableChannel中的keys
*/
protected final void deregister(AbstractSelectionKey key) {
((AbstractSelectableChannel) key.channel()).removeKey(key);
}
/*▲ 注册/反注册 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 打开/关闭 ████████████████████████████████████████████████████████████████████████████████┓ */
// 判断选择器是否处于开启状态
public final boolean isOpen() {
return selectorOpen.get();
}
/**
* Closes this selector.
*
* <p> If the selector has already been closed then this method returns
* immediately. Otherwise it marks the selector as closed and then invokes
* the {@link #implCloseSelector implCloseSelector} method in order to
* complete the close operation. </p>
*
* @throws IOException If an I/O error occurs
*/
// 关闭选择器
public final void close() throws IOException {
// 先标记选择器为关闭
boolean open = selectorOpen.getAndSet(false);
if(!open) {
return;
}
// 完成关闭选择器的后续逻辑,主要是释放资源
implCloseSelector();
}
/**
* Closes this selector.
*
* <p> This method is invoked by the {@link #close close} method in order
* to perform the actual work of closing the selector. This method is only
* invoked if the selector has not yet been closed, and it is never invoked
* more than once.
*
* <p> An implementation of this method must arrange for any other thread
* that is blocked in a selection operation upon this selector to return
* immediately as if by invoking the {@link
* java.nio.channels.Selector#wakeup wakeup} method. </p>
*
* @throws IOException If an I/O error occurs while closing the selector
*/
// 完成关闭选择器的后续逻辑,包括关闭通道、管道,结束辅助线程,释放分配的本地内存
protected abstract void implCloseSelector() throws IOException;
/*▲ 打开/关闭 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 取消 ████████████████████████████████████████████████████████████████████████████████┓ */
// 取消指定的"选择键",即将其加入到"已取消键临时集合"(cancelledKeys)中
void cancel(SelectionKey selectionKey) {
synchronized(cancelledKeys) {
cancelledKeys.add(selectionKey);
}
}
/**
* Retrieves this selector's cancelled-key set.
*
* <p> This set should only be used while synchronized upon it. </p>
*
* @return The cancelled-key set
*/
// 返回"已取消键临时集合"
protected final Set<SelectionKey> cancelledKeys() {
return cancelledKeys;
}
/*▲ 取消 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 中断回调标记 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Marks the beginning of an I/O operation that might block indefinitely.
*
* <p> This method should be invoked in tandem with the {@link #end end}
* method, using a {@code try} ... {@code finally} block as
* shown <a href="#be">above</a>, in order to implement interruption for
* this selector.
*
* <p> Invoking this method arranges for the selector's {@link
* Selector#wakeup wakeup} method to be invoked if a thread's {@link
* Thread#interrupt interrupt} method is invoked while the thread is
* blocked in an I/O operation upon the selector. </p>
*/
// 在一段可能阻塞的I/O操作开始之前,设置线程中断回调标记
protected final void begin() {
if(interruptor == null) {
interruptor = new Interruptible() {
public void interrupt(Thread ignore) {
// 通过哨兵元素唤醒阻塞的线程(选择器),并设置interruptTriggered = true
AbstractSelector.this.wakeup();
}
};
}
// 为当前线程设置线程中断回调标记
AbstractInterruptibleChannel.blockedOn(interruptor);
Thread me = Thread.currentThread();
// 测试线程是否已经中断,线程的中断状态不受影响
if(me.isInterrupted()) {
// 如果线程已经中断了,那么立即执行interruptor中的逻辑
interruptor.interrupt(me);
}
}
/**
* Marks the end of an I/O operation that might block indefinitely.
*
* <p> This method should be invoked in tandem with the {@link #begin begin}
* method, using a {@code try} ... {@code finally} block as
* shown <a href="#be">above</a>, in order to implement interruption for
* this selector. </p>
*/
// 移除之前设置的线程中断回调标记
protected final void end() {
AbstractInterruptibleChannel.blockedOn(null);
}
/*▲ 中断回调标记 ████████████████████████████████████████████████████████████████████████████████┛ */
/**
* Returns the provider that created this channel.
*
* @return The provider that created this channel
*/
// 返回构造当前选择器的选择器工厂
public final SelectorProvider provider() {
return provider;
}
}