Netty第二章 2020 3-3——Netty源码之Server端Worker线程组的启动

本文详细剖析了Netty服务器端Boss线程组与Worker线程组在处理客户端连接时的交互过程。从客户端发起连接开始,Boss线程负责监听并接受连接,然后将任务交给Worker线程执行。通过NioEventLoop的运行流程,展示了从select操作到任务执行的整个链路,阐述了Boss线程和Worker线程如何协作处理网络I/O操作。
摘要由CSDN通过智能技术生成

Server端会接收客户端发起的连接操作,然后启动worker线程组。

Server和Client端的交互

上文(Netty第二章 2020 3-2——Netty源码之Server端Boss线程组的启动_普通网友的博客-CSDN博客)提到了,NioEventLoop中有两个重要的操作,分别是NioEventLoop.processSelectedKeys和SingleThreadEventExecutor.runAllTasks。说完了runAllTasks,下面说下processSelectedKeys。

1.调用链

当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

上图加深记忆:

SingleThreadEventExecutor

NioEventLoop

NioEventLoop

NioEventLoop

NioEventLoop

AbstractNioMessageChannel

DefaultChannelPipeline

DefaultChannelPipeline

AbstractChannelHandlerContextServerBootstrap$ServerBootstrapAcceptor

MultithreadEventLoopGroup(回到了熟悉的地方)

SingleThreadEventLoop

后面省略

2.Boss线程和Worker线程的交替

下面看下最关键的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线程执行的。

2.Worker的NioEventLoop取任务

Worker的NioEventLoop是如何取任务的呢?通过上面的调用链可以知道,是在NioEventLoop的run方法中,一个死循环,processSelectedKeys发现selectedKeys的个数大于0了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值