1

我正在编写另一个 NIO 服务器。有一个选择器线程执行读取、处理(大多数情况下)和写入(下面的伪代码,不是真正的 Java):

while (true) {
    select();

    for (key : keys) {
        if (isReading(key)) {
            data = read(key.channel());

            result = process(data);

            key.interestOps(OP_WRITE);
        }

        if (isWriting(key)) {
            key.channel().write(result);
        }
    }
}

大多数情况下的处理是微不足道的,所以应该没问题。但是,有(极少数)情况下,处理是耗时的,应该委托给另一个线程。因此,该线程应该以某种方式告诉选择器在处理完成时对 OP_WRITE 感兴趣。

正如我所见,至少有两种方法可以做:

  1. 调用 wakeup() 和 register() 以使用同步在同一(工作)线程中进行写入,以防止下一个 select() 发生而不导致 register() 挂起。
  2. 将“注册”操作入队,然后在工作线程中调用 wakeup() 以允许选择器线程将操作出列以注册以在同一线程中写入。

我的问题是:如果我选择方法#2,我是否必须使用线程安全的队列实现(比如 ConcurrentLinkedQueue)?我怀疑我不会因为 enqueue() “之前发生” dequeue() 这是由 wakeup() 调用保证的,但我无法正式证明这一点。

请帮忙!谢谢!

4

1 回答 1

1

根据我的评论,您的问题是建立在谬误之上的。您不需要“在处理完成时告诉选择器对 OP_WRITE 感兴趣”。您只需在创建响应时编写响应。只有在写入返回零的情况下,才需要对通道的 OP_WRITE 中的选择器感兴趣。

要回答您的补充问题,请select()参与三个记录的同步级别。wakeup()不会,但您通常会wakeup()在选择器上同步一个块,在其中您可以使用选择器下次选择时需要知道的任何内容。这完成了所有必要的“事前发生”关系。

于 2017-10-10T01:03:35.790 回答