1. 程式人生 > >Netty原始碼分析:1.2初始化NioEventLoop

Netty原始碼分析:1.2初始化NioEventLoop

第一章節是主要是伺服器啟動的程式碼分析。章節目錄有:
|———1.1初始化NioEventLoopGroup
|———1.2初始化NioEventLoop
|———1.3初始化NioServerSocketChannel
|———1.4伺服器啟動流程
為什麼先從初始化開始瞭解伺服器啟動?
因為在我看伺服器啟動的相關原始碼的時候,有很多地方都是初始化的時候已經建立好的。所以我就從初始化的原始碼開始看起。這是我第一次看原始碼的筆記,仍有很多理解錯誤的地方和不解的地方。歡迎討論。

本篇目錄:

  • 繼承類關係圖
  • 初始化流程圖
  • 程式碼分析
  • 疑問

繼承類關係圖

image.png

初始化流程圖

image.png

1 NioEventLoop

  • 1 初始化父類SingleThreadEventLoop
  • 分析一下NioEventLoop構造的引數
    第一個引數NioEventLoopGroup parent :該NioEventLoop所在的執行緒池
    第二個引數Executor executorThreadPerTaskExecutor(newDefaultThreadFactory()) 的一個執行器。
    第三個引數SelectorProvider:主要是provider.openSelector()開啟Selector。
    第四個引數SelectStrategy
    :一個選擇策略,當執行緒進行事件迴圈的時候,就是根據該類來進行判斷。
    第五個引數RejectedExecutionHandler:一個處理異常的類
    此時父類已經初始化完成,接下來是NioEventLoop類的一個初始化。
  • 2 獲得一個SelectorTuple物件,該物件其實裝著Selector。這一步就是通過selectorProvider獲得Selector的
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
         //1
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler); if (selectorProvider == null) { throw new NullPointerException("selectorProvider"); } if (strategy == null) { throw new NullPointerException("selectStrategy"); } provider = selectorProvider; final SelectorTuple selectorTuple = openSelector();//2 selector = selectorTuple.selector; unwrappedSelector = selectorTuple.unwrappedSelector; selectStrategy = strategy; }

SingleThreadEventLoop

NioEventLoop 父類的SingleThreadEventLoop有參構造
有兩個新引數
第一個int addTaskWakesUp: 預設值 false
第二個int maxPendingTasks: 預設值DEFAULT_MAX_PENDING_TASKS
- 1 對父類進行初始化
- 2 建立一個LinkedBlockingQueue的任務佇列

protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,
                                    boolean addTaskWakesUp, int maxPendingTasks,
                                    RejectedExecutionHandler rejectedExecutionHandler) {
         //1
        super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);
        tailTasks = newTaskQueue(maxPendingTasks); //2
    }

SingleThreadEventExecutor

SingleThreadEventLoop 父類的SingleThreadEventLoop有參構造
- 1 是最終對父類AbstractEventExecutor的一個變數EventExecutorGroup 複製。
- 2 賦值給addTaskWakesUp ,當該執行緒有新增任務的時候就會改為ture,用來喚醒執行緒
- 3 賦值給maxPendingTasks,該執行緒最大允許任務數
- 4 建立一個任務佇列

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
                                        boolean addTaskWakesUp, int maxPendingTasks,
                                        RejectedExecutionHandler rejectedHandler) {

        super(parent);//1
        this.addTaskWakesUp = addTaskWakesUp;//2
        this.maxPendingTasks = Math.max(16, maxPendingTasks); //3
        this.executor = ObjectUtil.checkNotNull(executor, "executor"); 
        taskQueue = newTaskQueue(this.maxPendingTasks); //4
        rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
    }

總結

NioEventLoop類實現的是單執行緒處理多個channel或者channel。那麼它就應該是具有channel的一些資訊以及與一條thread執行緒繫結在一起。如圖:
image.png

疑問

  1. SingleThreadEventLoop 建立了一個tailTasks任務佇列,在SingleThreadEventExecutor建立了一個taskQueue任務佇列。他們分別有什麼用?
    我也不太懂,應該是擴充套件設計吧。
  2. SingleThreadEventExecutor 有兩個 Executor 和Thread 變數。分別代表什麼意思?
    在4.0.x 版本,只有Thread 這個變數。在初始化的時候,SingleThreadEventExecutor有參構造會建立一個thread執行緒。並將這個執行緒賦予給Thread變數。
    而在4.1.x 版本。就有 Executor 和Thread 變數兩個變數。在初始化的時候,是賦予 Executor 變數一個ThreadPertTaskExcutor物件。此時並沒有用該Executor建立一個執行緒,thread也是空的。 直到呼叫 SingleThreadEventExecutor 的execute()方法 才會生成一個執行緒並賦值與Thread變數