Netty原始碼分析:1.2初始化NioEventLoop
阿新 • • 發佈:2018-11-21
第一章節是主要是伺服器啟動的程式碼分析。章節目錄有:
|———1.1初始化NioEventLoopGroup
|———1.2初始化NioEventLoop
|———1.3初始化NioServerSocketChannel
|———1.4伺服器啟動流程
為什麼先從初始化開始瞭解伺服器啟動?
因為在我看伺服器啟動的相關原始碼的時候,有很多地方都是初始化的時候已經建立好的。所以我就從初始化的原始碼開始看起。這是我第一次看原始碼的筆記,仍有很多理解錯誤的地方和不解的地方。歡迎討論。
本篇目錄:
- 繼承類關係圖
- 初始化流程圖
- 程式碼分析
- 疑問
繼承類關係圖
初始化流程圖
1 NioEventLoop
- 1 初始化父類
SingleThreadEventLoop
- 分析一下NioEventLoop構造的引數
第一個引數NioEventLoopGroup parent
:該NioEventLoop所在的執行緒池
第二個引數Executor executor
:ThreadPerTaskExecutor(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執行緒繫結在一起。如圖:
疑問
- 在
SingleThreadEventLoop
建立了一個tailTasks任務佇列,在SingleThreadEventExecutor
建立了一個taskQueue任務佇列。他們分別有什麼用?
我也不太懂,應該是擴充套件設計吧。 - 在
SingleThreadEventExecutor
有兩個 Executor 和Thread 變數。分別代表什麼意思?
在4.0.x 版本,只有Thread 這個變數。在初始化的時候,SingleThreadEventExecutor
有參構造會建立一個thread執行緒。並將這個執行緒賦予給Thread變數。
而在4.1.x 版本。就有 Executor 和Thread 變數兩個變數。在初始化的時候,是賦予 Executor 變數一個ThreadPertTaskExcutor物件。此時並沒有用該Executor建立一個執行緒,thread也是空的。 直到呼叫SingleThreadEventExecutor
的execute()方法 才會生成一個執行緒並賦值與Thread變數