我正在编写另一个 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);
}
}
}
大多数情况下的处理都很简单,所以应该没问题。然而,在某些(罕见)情况下,处理非常耗时,应该委托(delegate)给另一个线程。因此,该线程应该以某种方式告诉选择器在处理完成时对 OP_WRITE 感兴趣。
据我所知,至少有两种方法可以实现:
- 使用同步在同一(工作)线程中调用wakeup()和register()进行写入,以防止下一个select()发生,从而不会导致register()挂起。
- 将“注册”操作加入队列,然后在工作线程中调用wakeup(),以允许选择器线程将操作出列,以便在同一线程中进行注册写入。
我的问题是:如果我选择方法 #2,我是否必须使用线程安全队列实现(例如 ConcurrentLinkedQueue)?我怀疑我不知道,因为 enqueue() “发生在” dequeue() 之前,这是由wakeup() 调用保证的,但我无法正式证明这一点。
请帮忙!谢谢!
最佳答案
根据我的评论,你的问题是基于一个谬论。您不需要“在处理完成时告诉选择器对 OP_WRITE 感兴趣”。您只需在创建响应后编写响应即可。只有在写入返回零的情况下,才有必要让选择器对 channel 的 OP_WRITE 感兴趣。
为了回答您的补充问题,select()
参与三个已记录的同步级别。 wakeup()
不会,但您通常会在 wakeup()
之后使用选择器上同步的 block ,在该 block 中您可以使用选择器下次选择时需要了解的任何内容。这完成了所有必要的先发生关系。
关于java - Selector.wakeup()和 "happens-before"的关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28754275/