EventLoop 接口
Netty 是基於 Java NIO 的,因此 Channel 也有其生命周期,處理一個連接在其生命周期內發生的事件是所有網絡框架的基本功能。通常來說,我們使用一個線程來處理一個連接,該連接的生命周期的某一事件就緒,則會調用對應的事件處理邏輯
在 Netty 中,一個 EventLoop 負責處理一個 Channel 的生命周期事件。在代碼設計上,EventLoop 間接實現了 JUC 中的 ExecutorService 和 ScheduleExecutorService 兩個接口,因此其具有了線程池的特性。一個 EventLoop 將由一個永遠不會改變的 Thread 驅動,EventLoop 由一個 Selector 和 TaskQueue 組成,Selector 會選擇 Channel 生命周期中某一事件,並由 EventLoop 所在的線程選擇對應的 ChannelHandler 進行處理。除此之外,用戶還可以手動提交任務給 EventLoop,以立即執行或調度執行
任務調度
有時候,你希望在 Channel 中調度一個任務以立即執行、稍后執行或者周期性執行。然而,這些任務有可能會造成長時間的阻塞,如果寫在 ChannelHandler 里面,則有可能會阻塞整個執行鏈。因此,我們可以把這些任務提交給 EventLoop,EventLoop 會把這些任務放入 TaskQueue 中,等待創建線程去執行,這個過程是異步非阻塞的,不會影響到主執行鏈
Channel ch = ...;
ScheduleFuture<?> future = ch.eventLoop().schedule(
// 創建一個 Runnable 以供調度稍后執行
new Runnable() {
@Override
public void run() {
// 要執行的代碼
System.out.println("60 second later");
}
}, 60, TimeUnit.SECONDS);
由此我們知道,EventLoop 所在線程負責一個 Channel 的整個生命周期內的所有事件。有時候,我們還會在別的線程去獲取一個 Channel,並向該 Channel 對應的 EventLoop 提交任務。這種非對應 Channel 所提交過來的任務,EventLoop 會把它放入任務隊列中,等待下次執行

EventLoop 的線程分配
服務於 Channel 的 EventLoop 包含在 EventLoopGroup 中,根據不同的傳輸實現,EventLoop 的創建和分配方式也不同
1. 異步傳輸
異步傳輸實現只使用了少量的 EventLoop,一個 EventLoop 可能會被多個 Channel 所共享,通過盡可能少的線程來支撐大量的 Channel,而不是每個 Channel 分配一個 Thread

需要注意的是,一個 EventLoop 被用於支撐多個 Channel,那么對於所有相關聯的 Channel 來說,ThreadLocal 是一樣的,這使得它對於實現狀態追蹤等功能來說是個糟糕的選擇
2. 阻塞傳輸
每一個 Channel 都將分配給一個 EventLoop,每個 Channel 的 IO 事件都將只會被一個 Thread 處理

