使用Selector和SelectionKeys委派给线程池

时间:2017-03-03 01:10:53

标签: java multithreading

我正在编写一个应用程序,其中主线程通过使用SelectorSelectionKeys来处理许多连接。在尝试将任务传递给工作线程时,我遇到了一些竞争条件的麻烦。

我的主循环看起来像这样:

    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异常。

1 个答案:

答案 0 :(得分:0)

您应该在select循环中执行read,然后启动worker来处理数据并准备响应,或者从选择键的MPMediaPlaylist中删除OP_READ,直到响应被发送为止。< / p>