其實在將這一節以前,咱們來分析一個東西,方便下面的工做好開展。算法
打開啓動類,最開始的時候建立了一個NioEventLoopGroup 事件循環組,咱們來跟一下這個。數組
這裏bossGroup, 我傳入了一個線程, workerGroup 沒有入參,默認0, 也就是說父級我用一個線程來處理客戶端的接入, 多個線程來處理客戶端的讀寫操做安全
經過一連串的構造方法進入到異步
executor 是 null , selectorProvider 用來建立一個多路複用器, 最後一個參數傳入了 一個多路複用器的一個策略, 這個策略咱們後面會講到ide
緊接着又傳入了一個拒絕策略, 因爲 NioEventLoopGroup 繼承了 MultithreadEventLoopGroup,因此進入 MultithreadEventLoopGroup 的構造方法oop
這裏的判斷, bossGroup 傳入了 1 ,因此nThreads = 1; workerGroup 沒有入參,默認是0 ,因此這裏到了一個判斷默認線程數的地方。性能
就是這了, NettyRuntime.availableProcessors() * 2 表明 CPU核心數 * 2(處理器超線程數) * 2的值 或 CPU數 * 2的值 spa
在cmd命令中輸入「wmic」,而後在出現的新窗口中輸入「cpu get *」。
NumberOfCores:表示CPU核心數
NumberOfLogicalProcessors:表示CPU線程數線程
因此我這裏是 CPU核心數 是 2 , CPU 線程數 是 4 , 因此個人 NettyRuntime.availableProcessors() * 2 = 8, 而後這裏Math.max(1,8) 取大的 就是 8 了blog
因此個人 workerGroup 線程數 是 8
好了,咱們繼續跟進去
這裏建立了一個線程工廠,主要是爲線程設置名字、是否守護進程、線程的優先級等等。而後建立一個任務執行器,把線程工廠傳進去賦給成員變量
這個executor 後面在每一個 事件執行器 建立子線程處理task來用
接下來建立一個長度是nThreads的 EventExecutor[] ,對於 子事件循環組來講,這裏實際上是建立了一個長度爲8 的NioEventLoop的數組, 即 EventExecutor[] children = new NioEventLoop[8]
這個地方我糾結了一下,由於我語文太差了,我決定畫個圖來展現一下, 雖然我美術也很差。
你們看下這個代碼層級結構, 其實就很顯而易見了,這裏我要說一下,SingleThreadEventExecutor 中有一個thread成員變量,說明每一個都只有一個線程來處理,而且含有任務隊列和任務的執行器。
另外每個NioEventLoop都含有一個selector 多路複用器 。
繼續看,這裏經過默認的選擇工廠來建立一個選擇器。
跟進去,咱們看到下面的這段代碼,不得不感嘆Netty真的已經把性能發揮到了極致,能用位運算的毫不會用數學計算法,因此這裏對選擇器進行了區分
看這個判斷方法,意思是 若是是 2的次方 ,那麼建立一個 PowerOfTwoEventExecutorChooser 選擇器
我特地去驗證了一個這個算法
結果是:
好了,講到這裏咱們能夠從新開始講註冊了,仍然進入 initAndRegister()方法
config().group() 這個獲取到的 是 ServerBootStrap.group(), 那麼也就是取到了 父級的事件循環組 也就是bossGroup
根據我上上圖的分析,那麼註冊方法進入的確定是 MultithreadEventLoopGroup
這裏有一個next()方法,用來選擇一個NioEventLoop。因爲我這裏是1個線程的數組,因此進入
所以,對於bossGroup來講,就是 0 & 0 = 0 1 & 0 = 0 2 & 0 = 0 .....
對於workerGroup來講,就是 0 & 7 = 0 1 & 7 = 1 2 & 7 = 2 .... 8 & 7 = 0 9 & 7 = 1 ....
因此這裏實際上是一個輪詢的算法。
ok, 看到這裏咱們猜想是 從 new NioEventLoop[1] 中輪詢一個 NioEventLoop, 而後把channel註冊到上面的多路複用器上。
繼續看, 根據那個流程圖,能夠推斷出是進入到 SingleThreadEventLoop
接着傳入了一個 DefaultChannelPromise ,用來作註冊結果的異步通知的。傳入了channel 和 當前的這個 SingleThreadEventLoop ,固然具體怎麼異步通知的,咱們後面會講到
繼續看
這裏把剛剛選擇出來的 NioEventLoop 賦給 Channel 的 eventLoop 的成員變量, 這裏也就意味着 ,這個NioEventLoop 也將一直伴隨 這個channel 的全部的讀寫操做, 由於經過上面的那個流程圖代表了 一個NioEventLoop 上面只有一個Thread , 那麼也能夠得出 一個Channel 整個週期 內全部的讀寫操做,所有由同一個Thread來完成, 這也就說明了爲何Netty沒有線程安全問題,固然隨着後面的講解,你將會對這個地方理解的更加的深入。
好了,註冊的內容咱們下一節接着說。