我有一个Thread
带有私有Selector
和公共register(SelectableChannel channel, ...)
方法的子类,它允许其他线程将通道注册到选择器。
正如这里回答的那样,通道register()
在选择器select()
/期间阻塞,select(long timeout)
所以我们需要wakeup()
选择器。
我的线程无限期地选择(除非它被中断)并且它实际上设法在register()
调用通道之前进入下一个选择。所以我想我用一个带synchronized
块的简单锁来确保register()
首先发生。
代码:(为了便于阅读,删除了不相关的代码)
public class SelectorThread extends Thread {
...
public void register(SelectableChannel channel, Attachment attachment) throws IOException {
channel.configureBlocking(false);
synchronized (this) { // LOCKING OCCURS HERE
selector.wakeup();
channel.register(selector,
SelectionKey.OP_READ,
attachment);
}
}
@Override
public void run() {
int ready;
Set<SelectionKey> readyKeys;
while (!isInterrupted()) {
synchronized (this) {} // LOCKING OCCURS HERE
try {
ready = selector.select(5000);
} catch (IOException e) {
e.printStackTrace();
continue;
}
if (ready == 0) {
continue;
}
readyKeys = selector.selectedKeys();
for (SelectionKey key : readyKeys) {
readyKeys.remove(key);
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
...
}
}
}
}
}
This simple lock allows register()
to happen before the thread continues with the next select loop. As far as I tested, this works as supposed.
Questions: Is that a "good" way to do it or are there any serious downsides to that? Would it be better to use a List or Queue (as suggested here) to store channels for registration, or a more sophisticated lock like this instead? What would the Pros/Cons of that be? Or are there any "even better" ways?