上文(https://blog.csdn.net/xxcupid/article/details/104797073)提到了,NioEventLoop中有两个重要的操作,分别是NioEventLoop.processSelectedKeys和SingleThreadEventExecutor.runAllTasks。说完了runAllTasks,下面说下processSelectedKeys。
当client端发起连接的时候:
Boss线程部分:
run:408, NioEventLoop
select:753, NioEventLoop
select:62, SelectedSelectionKeySetSelector
select:97, SelectorImpl
lockAndDoSelect:86, SelectorImpl
doSelect:122, KQueueSelectorImpl->这个具体实现看平台,我用过mac来调试的,所以这里是KQueue的实现。
updateSelectedKeys:169, KQueueSelectorImpl
add:35, SelectedSelectionKeySet->使得selectedKeys中的元素个数大于0,这里的SelectionKey的readyOps和interestOps是16,是OP_ACCEPT
同时,在NioEventLoop的死循环中有对应判断,
run:458, NioEventLoop
processSelectedKeys:496, NioEventLoop
processSelectedKeysOptimized:571, NioEventLoop->这里的for循环的seletedKeys.size>0
processSelectedKey
channelRead:1434, DefaultChannelPipeline$HeadContext
fireChannelRead:340, AbstractChannelHandlerContext
invokeChannelRead:348, AbstractChannelHandlerContext
invokeChannelRead:362, AbstractChannelHandlerContext
channelRead:255, ServerBootstrap$ServerBootstrapAcceptor->这里注意,用childGroup去注册channel(这里是SocketChannel),同时childGroup对应的是worker线程组,会启动Worker对应的NioEventLoop的线程
register:86, MultithreadEventLoopGroup->这里用next()选出合适的NioEventLoop(它里面的thread是Worker线程),这个注册操作和boss线程组最开始注册的模式是一样的,只是Factory选择的是Worker组。
register:74, SingleThreadEventLoop
register:80, SingleThreadEventLoop
register:479, AbstractChannel$AbstractUnsafe->eventLoop.execute
execute:778, SingleThreadEventExecutor
addTask:318, SingleThreadEventExecutor->(当前执行线程是boss线程)添加任务到当前NioEventLoop的taskQueue中,该NioEventLoop是Worker线程组的,注意,此时还没有调用startThread方法,所以该NioEventLoop的thread还是空的,没有初始化的
run:462, NioEventLoop->该Worker的NioEventLoop初始化后,会执行该run方法死循环
runAllTasks:404, SingleThreadEventExecutor->这里会取出上面通过addTask方法添加的任务来执行
==============接着在死循环中还要继续执行下面操作,这里用线分开,避免混淆
select:753, NioEventLoop
lockAndDoSelect:86, SelectorImpl
updateSelectedKeys:169, KQueueSelectorImpl
add:35, SelectedSelectionKeySet->再次添加,使得selectedKeys中的元素个数大于0,这里的SelectionKey的readyOps和interestOps是1,是OP_READ
下面看下最关键的boss和worker两个不同的线程交接任务的点:
register:86, MultithreadEventLoopGroup->这里用next()选出合适的NioEventLoop(它里面的thread是Worker线程)
register:74, SingleThreadEventLoop
register:80, SingleThreadEventLoop
register:479, AbstractChannel$AbstractUnsafe->eventLoop.execute
execute:778, SingleThreadEventExecutor->这里addTask因为是调用的该Worker的tNioEventLoop的addTask方法,所以该task放到了Worker的NioEventLoop中,注意,虽然当前执行线程是boss线程,但是操作的是Worker的NioEventLoop,所以inEventLoop判断是false,然后执行startThread方法来启动线程。
后面该Worker的NioEventLoop的死循环会取出来这个任务执行,所以会发现ChannelInboundHandlerAdapter的channelRead方法是由Worker线程执行的。
Worker的NioEventLoop是如何取任务的呢?通过上面的调用链可以知道,是在NioEventLoop的run方法中,一个死循环,processSelectedKeys发现selectedKeys的个数大于0了。