Netty2020 3-2——Netty源碼之Server端Boss線程組的啓動

以主從Reactor爲例,Server在啓動的時候,會創建Boss和Worker兩個EventLoopGroup,這兩個group會作爲參數傳入到ServerBootstrap的group方法中。

1.Boss組線程的啓動:

1) 用戶線程部分:

AbsttractBootstrap.bind->綁定端口

AbsttractBootstrap.initAndRegister->初始化channel並註冊channel

MultithreadEventLoopGroup.register

SingleThreadEventLoop.register

AbstractChannel.register

SingleThreadEventExecutor.execute

SingleThreadEventExecutor.startThread->這個只會在初始化的時候start一次,因爲inEventLoop是false。

SingleThreadEventExecutor.doStartThread

ThreadPerTaskExecutor.execute->4.1.X新加入的方法,將用工廠創建線程並啓動執行任務的動作封裝了起來,也是真正啓動Boss線程的地方,之前都是用戶線程。

2) Boss線程部分:

SingleThreadEventExecutor.this.run

NioEventLoop.run->這裏是一個死循環,在ratio不是100的時候,會一直跑任務,主要工作有兩個:

NioEventLoop.processSelectedKeys 和 SingleThreadEventExecutor.runAllTasks。

下面先說下SingleThreadEventExecutor.runAllTasks。

3) Boss線程組創建並啓動的線程數量

無論你在構造EventLoopGroup的時候的入參傳入的nThreads是多少,真正創建並啓動的Boss線程的個數只和bind的端口數有關。如果server只綁定了一個端口(大部分服務器都是隻綁定一個端口),那麼及時nThreads>1,那麼也只會啓動一個Boss線程。

因爲這個線程的啓動是bind動作的附屬操作(bind中的register0),所以和bind的次數相關。

2.任務的添加和執行

接上面,在ThreadPerTaskExecutor.execute執行,也就是真正啓動線程之後,執行取任務操作:

SingleThreadEventExecutor.runAllTasks->這裏會取兩種不同的task,定時任務也會被添加到taskQueue中

SingleThreadEventExecutor.fetchFromScheduledTaskQueue->最開始定時的task沒有

SingleThreadEventExecutor.pollTask->普通task有一個元素,就是上面說的啓動線程之前添加進去的register的task

AbstractEventExecutor.safeExecute->poll出來的任務都在這裏執行

3.任務的添加和執行

在Boss線程組啓動之前,SingleThreadEventExecutor.execute中會先添加一個task,該task是註冊channel,這是第一個添加進去的任務register0:

AbstractChannel$AbstractUnsafe.register0

該任務又會衍生出兩個其他任務,這兩個衍生任務在register0方法中。

四個任務

1) 第一個衍生任務

invokeHandlerAddedIfNeeded:686, DefaultChannelPipeline

callHandlerAddedForAllHandlers:1161, DefaultChannelPipeline

execute:1487, DefaultChannelPipeline$PendingHandlerAddedTask

handlerAdded:107, ChannelInitializer->在上面添加完handler之後,初始化channel

initChannel:178, ServerBootstrap$1->向pipeline中添加ChannelHandler

execute:773, SingleThreadEventExecutor->添加的動作在這個execute中執行

SingleThreadEventExecutor->addTask->這裏,該衍生任務添加到taskQueue中

所以,到此,又回到了上面提到的那個流程,只是這次在execute方法中,inEventLoop是true,不用再啓動boss線程了。

2) 第二個衍生任務

safeSetSuccess:978, AbstractChannel$AbstractUnsafe

notifyListenersNow:485, DefaultPromise

notifyListener0:511, DefaultPromise

operationComplete:296, AbstractBootstrap$1

doBind0:362, AbstractBootstrap

execute:773, SingleThreadEventExecutor->這裏又回到了熟悉的流程裏

3) 第二個衍生任務又會衍生一個任務

接上面:

bind:254, AbstractChannel

bind:1019, DefaultChannelPipeline

bind:486, AbstractChannelHandlerContext

invokeLater:1012, AbstractChannel$AbstractUnsafe

SingleThreadEventExecutor.execute的4次執行

第一次,調用線程是用戶線程,是bind->register的時候,register:479, AbstractChannel$AbstractUnsafe,會啓動boss線程。

第二次,調用線程是Boss線程,register0:510, AbstractChannel$AbstractUnsafe,invokeHandlerAddedIfNeeded:686, DefaultChannelPipeline。

第三次,調用線程是Boss線程,register0:512, AbstractChannel$AbstractUnsafe,safeSetSuccess:978, AbstractChannel$AbstractUnsafe。

第四次,調用線程是Boss線程,bind:486, AbstractChannelHandlerContext,invokeLater:1012, AbstractChannel$AbstractUnsafe

對應的四次addTask添加任務

第一次,任務是register0

第二次,register0的衍生操作,pipeline.addLast,添加ChannelHandler

第三次,register0的衍生操作,doBind0中的Channel.bind操作

第四次,doBind0的衍生操作,bind:566, AbstractChannel$AbstractUnsafe,invokeLater:1012, AbstractChannel$AbstractUnsafe,task任務是pipeline.fireChannelActive()

 

後面會詳解一下pipeline.fireChannelActive註冊連接事件這塊。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章