java nio Selector唤醒

时间:2009-11-04 15:56:30

标签: java nio

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

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

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

唤醒方法的javadoc说明:

  

如果当前阻止了其他线程   在调用   Selector.select()或   然后选择Selector.select(long)方法   该调用将返回   立即

P.S很少有其他解决办法;其中一个是选择(超时),但我试图找出错误的位置。

伪代码:

第一线:

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);

}

1 个答案:

答案 0 :(得分:4)

如果你在选择器中注册它,你可能不希望线程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()来说为时已晚)
  9. 我建议让线程2设置一个SocketChannel,将它存放在线程1可以获取的地方(确保在执行此操作时是线程安全的),然后唤醒选择器,让它检查它的现有密钥在线程1中,让线程1在再次调用Selector.select()之前注册新的SocketChannel。