我正在写另一个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感兴趣。

如我所见,至少有两种方法可以执行:


使用同步在同一线程(工作线程)中调用wakeup()和register()以进行写入操作,以防止发生下一个select()不会导致register()挂起的情况。
使“注册”操作入队,然后在辅助线程中调用akeup(),以允许选择器线程使该操作出队以注册以在同一线程中进行写入。


我的问题是:如果选择方法2,是否必须使用线程安全队列实现(例如ConcurrentLinkedQueue)?我怀疑自enqueue()“先于happens-before” dequeue()以来,我没有这样做,而该问题由wakeup()调用来保证,但是我无法正式证明这一点。

请帮忙!谢谢!

最佳答案

根据我的评论,您的问题基于谬论。您无需“在处理完成后告诉选择器对OP_WRITE感兴趣”。创建响应后,您只需编写响应即可。仅在该写返回零的情况下,才有必要对该通道的OP_WRITE中的选择器感兴趣。

为了回答您的补充问题,select()参与了三个记录的同步级别。 wakeup()不会,但是您通常会遵循wakeup(),在选择器上同步一个块,在该块中,您可以玩选择器下次选择时需要知道的所有内容。这样就完成了所有必要的事前关系。

09-27 18:48