我有一个继承了 Thread
的子类,它有一个私有的 Selector
和一个公共的 register(SelectableChannel channel, ...)
方法,允许其他线程将通道注册到选择器中。
正如这里所回答的,当选择器的 select()
/ select(long timeout)
被调用时,通道的 register()
会被阻塞,因此我们需要使用 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()) {
...
}
}
}
}
}
这个简单的锁允许在线程继续下一个选择循环之前进行register()
。据我测试,这个方法是可行的。
问题: 这是一种“好”的方式吗?还是有什么严重的缺点?使用List或Queue(如此处所建议)来存储通道以进行注册,或者使用类似这个更复杂的锁会更好吗?这样做的优缺点是什么?还有任何“更好”的方法吗?