为什么这里要重复调用readNextMessage()?
来源:7-12 NIO服务器Thread优化-6
树那边
2019-05-11
按照我的理解是readNextMessage只需要调用一次,然后有消息来的时候这个onCompleted方法就会被调用,我的理解问题出在哪?
2回答
-
这个地方在于对于Selector的理解。
当我们在Selector上注册一个监听后,如果事件就绪就会从select方法中得到。此时可以进行事件处理。
但是这里有一个较大的问题,如果在多并发的情况下,我们一个线程专门负责Selector.select()操作,那么当有通道就绪时此时我们不断的调用Selector.select()将每次都得到这个就绪的通道。我们的流程是:A线程Selector.select()得到就绪通道,将通道丢进线程池,等待线程池中的线程 B、C、D等运行。这个过程肯定不是单线的,而是多并发的。
那么当线程池还没处理完这个事件之前,我们每次Selector.select()都会得到这个通道;然后又会重复丢进线程池;这就有矛盾了,一旦发生这样的事情,那么就会出现同一个通道的数据被多个线程同时操作的情况,也就会出现数据混乱问题。对于一段字符串:“Hello”可能一个线程读取了其中一部分。但是却无法正确组合在一起。
那么这个时候我们在Selector.select()之后就做了一件事件,将已就绪的通道全部解除注册,那么下一次调度Selector.select()就不会得到这些就绪的通道了,从而避免上述问题。
当然这样的做法就需要有一个完整的闭环:
注册-等到Selector.select()-已就绪-解除注册-丢进线程池-等待线程调度-处理调度-读取数据-再次注册下一次调度
所以我们需要在完成方法调度时再次调用:
readNextMessage
012019-05-11 -
树那边
提问者
2019-05-11
好的,理解了谢谢老师,那么如果已就绪的通道全部解除注册,这时这些解除注册的通道对应的客户端有消息来了就得不到监听了,这些消息会被遗弃掉吗?还是说当这些通道重新注册时(如果之前有消息来了)又会处于就绪状态?
022019-05-11
相似问题