在前面的分析中介绍过,Acceptor的作用是控制与tomcat建立连接的数量,但Acceptor只负责建立连接。socket内容的读写是通过Poller来实现的。
Poller使用java nio来实现连接的管理。
关于nio,主要需要明确三个概念:Channel、Selector和SelectionKey.
在这里的使用上,它们之间的关系可以简单这样理解,Channel必须注册到Selector上才能用于接收socket数据,在Selector上有数据到达的Channel可以用SelectionKey来表示
[注册]
Poller使用nio来进行socket数据的读写,一个通过Poller的register方法,注册到Poller上。
对Poller的注册,先进入Poller内部维护的一个事件队列上。Poller线程在执行过程中会去检查队列,将channel注册到selector上。为了保证在多线程同时访问时数据的一致性,这个队
列是一个SynchronizedQueue,使用synchronized来保证对队列中数据的一致性。
注册的时候,每个channel会有KeyAttachment对象,用来进行channel上的多线程并发执行时的控制。
ServerSocketChannel建立连接是在Acceptor上。
[队列]
队列定义如下
private
final
SynchronizedQueue<PollerEvent> events =
new
SynchronizedQueue<>();
队列中的每个元素是PollerEvent对象,它携带完成的处理channel相关的信息。每个事件在处理过程中,会根据事件的状态,来实现Channel到Selector上的注册。队列处理完成后,每个注册到Poller上的channel就完成了到Selector上的注册。
[socket数据读取]
Poller线程的run方法的主题部分使用while(true)的无限循环来执行,当所属的Endpoint正常运行的时候,在每次执行过程中,处理其事件队列,调用selector来读取数据,然后处理读取到的数据。
在run方法中,会调用 events方法来处理事件队列