Java NIO选择器在调用select()时何时解除阻塞?

3

我正在学习NIO包。我参考了这里的NioServer示例。在NioServer.java中,选择器线程会阻塞在

this.selector.select(); 
Iterator<SelectionKey> selectedKeys = this.selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
    SelectionKey key = selectedKeys.next();
    selectedKeys.remove();
    if (!key.isValid()) {
        continue;
    }

    if (key.isAcceptable()) {
        this.accept(key);
    } else if (key.isReadable()) {
        this.read(key);
    } else if (key.isWritable()) {
        this.write(key);
    }

当远程客户端连接时,会调用this.accept(key)方法,在这个方法中将interestOps更改为Read并唤醒选择器。 是这个操作导致选择器选择此通道吗?因此,我们通过这种方式发出信号以选择通道。
现在假设在向套接字通道写入数据时,通过更改通道的interest来通知选择器该通道已准备好进行写入。 但是,如果由于套接字缓冲区已满而导致写入未完成,那么我们不会更改interest并将其保持为仅写入。 那么,选择器何时会选择此通道呢?

1
你应该避免无限期地阻塞,而是使用重载的select(long timeout)方法。 - Schildmeijer
2个回答

3
  1. this.accept(key) 调用 serverSocketChannel.accept() 方法,该方法返回一个用于与客户端通信的 socket channel。这个 channel 被注册到 selector 上以进行 "read" 操作,因此 selector 现在有 两个 注册:

    • 原始的 ServerSocketChannel,使用 OP_ACCEPT
    • 新客户端的 SocketChannel,使用 OP_READ
  2. 如果写入无法完成,由于缓冲区已满,相应的 SocketChannel 仍然使用 OP_WRITE 注册。一旦客户端从另一端读取了一些数据,channel 将再次被选中,允许我们在将 interest set 切换回 OP_READ 之前写入剩余的数据。


1

当套接字发送缓冲区有空间时,OP_WRITE 触发。

NB 获取零长度的 write() 结果是使用 OP_WRITE 的唯一场合。大多数情况下都有空间,因此 OP_WRITE 将不断触发。您不希望这样,因此通常不会为通道注册 OP_WRITE:仅当它刚刚从写入返回零时才注册;并且在通过 OP_WRITE 重新触发完成写入后取消注册。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接