为什么这里要重复调用readNextMessage()?

来源:7-12 NIO服务器Thread优化-6

树那边

2019-05-11

按照我的理解是readNextMessage只需要调用一次,然后有消息来的时候这个onCompleted方法就会被调用,我的理解问题出在哪?图片描述

写回答

2回答

Qiujuer

2019-05-11

这个地方在于对于Selector的理解。

当我们在Selector上注册一个监听后,如果事件就绪就会从select方法中得到。此时可以进行事件处理。
但是这里有一个较大的问题,如果在多并发的情况下,我们一个线程专门负责Selector.select()操作,那么当有通道就绪时此时我们不断的调用Selector.select()将每次都得到这个就绪的通道。

我们的流程是:A线程Selector.select()得到就绪通道,将通道丢进线程池,等待线程池中的线程 B、C、D等运行。这个过程肯定不是单线的,而是多并发的。

那么当线程池还没处理完这个事件之前,我们每次Selector.select()都会得到这个通道;然后又会重复丢进线程池;这就有矛盾了,一旦发生这样的事情,那么就会出现同一个通道的数据被多个线程同时操作的情况,也就会出现数据混乱问题。对于一段字符串:“Hello”可能一个线程读取了其中一部分。但是却无法正确组合在一起。


那么这个时候我们在Selector.select()之后就做了一件事件,将已就绪的通道全部解除注册,那么下一次调度Selector.select()就不会得到这些就绪的通道了,从而避免上述问题。


当然这样的做法就需要有一个完整的闭环:

注册-等到Selector.select()-已就绪-解除注册-丢进线程池-等待线程调度-处理调度-读取数据-再次注册下一次调度


所以我们需要在完成方法调度时再次调用:

readNextMessage




0
1
树那边
好的,理解了谢谢老师,那么如果已就绪的通道全部解除注册,这时这些解除注册的通道对应的客户端有消息来了就得不到监听了,这些消息会被遗弃掉吗?还是说当这些通道重新注册时(如果之前有消息来了)又会处于就绪状态?0
2019-05-11
共1条回复

树那边

提问者

2019-05-11

好的,理解了谢谢老师,那么如果已就绪的通道全部解除注册,这时这些解除注册的通道对应的客户端有消息来了就得不到监听了,这些消息会被遗弃掉吗?还是说当这些通道重新注册时(如果之前有消息来了)又会处于就绪状态?

0
2
树那边
回复
Qiujuer
好的,谢谢!
2019-05-11
共2条回复

Socket网络编程进阶与实战 系统掌握Socket核心技术

理论+实践,系统且深入掌握Socket核心技术,从容应对各种Socket应用场景的不二之选

2314 学习 · 476 问题

查看课程