7

selector.wakeup();请指出/提供两个线程之间方法的工作示例。

我试图创建一个简单的程序,其中一个线程正在等待 selector.select() 方法。第二个线程创建一些套接字并尝试向选择器注册;第一个线程在其上被阻塞。

因此我需要使用选择器的wakeup方法,但不知何故第一个线程没有退出阻塞模式。

唤醒方法的 javadoc 指出:

如果另一个线程当前在调用 Selector.select() 或 Selector.select(long) 方法时被阻塞,则该调用将立即返回。

PS几乎没有其他解决方法;其中之一是 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);

}
4

1 回答 1

6

如果您在选择器中注册它,您可能不希望线程 2 中的套接字被阻塞(因为选择器用于非​​阻塞 I/O)。我认为让选择器处理与 OP_CONNECT 的连接也是常见的做法(使用 SocketChannel.finishConnection())。

看起来你在这里可能有潜在的竞争条件。想象一下这一系列事件:

  1. 线程 1:selector.select()
  2. ... 时间流逝 ...
  3. 线程 2:Thread1.selector.wakeup()
  4. 线程 1:检查密钥的可接受性
  5. 线程 1:检查键的可读性
  6. 线程1:循环
  7. 线程 1:selector.select()
  8. 线程2:尝试在选择器中注册(但是这个select()已经太晚了)

我建议让线程 2 设置一个 SocketChannel,将其存放在线程 1 可以访问的地方(确保执行此操作时线程安全),然后唤醒选择器,让它检查线程 1 中的现有键并让线程 1 在再次调用 Selector.select() 之前注册新的 SocketChannel。

于 2009-11-05T04:51:04.130 回答