我正在编写一个应用程序,其中主线程通过使用Selector
和SelectionKeys
来处理许多连接。在尝试将任务传递给工作线程时,我遇到了一些竞争条件的麻烦。
我的主循环看起来像这样:
selector = Selector.open(); //Create selector
serverSocketChannel = ServerSocketChannel.open(); //Create socket channel, configure blocking, and bind
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(PORT));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //Register channel to selector
ByteBuffer buffer = ByteBuffer.allocate(8000);
while(true){
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()){
SelectionKey key = iterator.next();
if(key.isAcceptable()){
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
}
if(key.isReadable()){
taskList.add(new ReadTask(key));
}
if(key.isWritable()){
}
iterator.remove();
}
}
这里的想法是当客户端尝试向服务器发送数据时,它会收到一个OP_READ感兴趣的密钥,然后用该密钥创建一个任务,以便线程池可以处理读取,以免阻塞主线程
问题是在将密钥传递给工作线程的过程中调用此循环,并且在调用taskList.add(new ReadTask(key));
和调用最终key.channel().read(buffer)
之间的整个时间,主要线程仍然在迭代,并且看到该键仍在被选中。在密钥的通道上调用读取后,密钥被标记为非活动状态,并且似乎没有被选择器选择,直到来自其中一个客户端的另一个合法写入提示再次激活密钥。 / p>
我有没有办法标记密钥,以便在不调用read的情况下将其添加回选择键列表?我已尝试selector.selectedKeys.remove(key)
,但这会产生ConcurrentModification异常。
答案 0 :(得分:0)
您应该在select循环中执行read,然后启动worker来处理数据并准备响应,或者从选择键的MPMediaPlaylist
中删除OP_READ,直到响应被发送为止。< / p>