题
请指出/给我提供一个工作示例 selector.wakeup();
两个线程之间的方法。
我尝试创建一个简单的程序,其中线程正在等待选择器.select() 方法。第二个线程创建一些套接字并尝试向选择器注册;第一个线程被阻塞。
因此我需要使用选择器 wakeup
方法,但不知何故,第一个线程没有退出阻塞模式。
唤醒方法的javadoc指出:
如果当前在selector.select()或selector.select(long)方法的调用中阻止了另一个线程,则该调用将立即返回。
P.S 几乎没有其他解决方法;其中之一是 select(timeout) 但我试图找出错误在哪里。
伪代码:
第一个线程:
static Selector selector = Selector.open();
while(true) {
int n = selectorGlobal.select();
selectorKeySet = selectorGlobal.selectedKeys().iterator();
while (selectorKeySet.hasNext()) {
selectionKey = selectorKeySet.next();
if (selectionKey.isReadable()) {
//do something
}
if(selectionKey.isAcceptable()) {
//accept
}
}
}
第二个线程:
while (itr.hasNext()) {
data = (String) itr.next();
String IP = data.get(0);
String Port = data.get(1);
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(true);
boolean isConnected = socketChannel.connect(new InetSocketAddress(IP, Port));
ClassName.selector.wakeup();
SelectionKey selectionKey = SelectSockets.registerChannel(ClassName.selector,
socketChannel, SelectionKey.OP_READ);
}
解决方案
如果您将线程 2 中的套接字注册到选择器中,您可能不希望该套接字被阻塞(因为选择器用于非阻塞 I/O)。我认为让选择器处理与 OP_CONNECT 的连接(使用 SocketChannel.finishConnection())也是常见的做法。
看起来这里也可能存在潜在的竞争条件。想象一下这一系列事件:
- 主题 1:选择器.select()
- ...时间流逝 ...
- 话题2:Thread1.selector.wakeup()
- 主题 1:检查密钥的可接受性
- 主题 1:检查按键的可读性
- 主题 1:环形
- 主题 1:选择器.select()
- 话题2:尝试在选择器中注册(但对于这个 select() 来说已经太晚了)
我建议让线程 2 设置一个 SocketChannel,将其存放在线程 1 可以访问的地方(确保执行此操作时线程安全),然后唤醒选择器,让它检查线程 1 中的现有键并让线程 1 在再次调用 Selector.select() 之前注册新的 SocketChannel。
不隶属于 StackOverflow