1、 BUG出現的原因:
若Selector的輪詢結果爲空,也沒有wakeup或新消息處理,則發生N多次空輪詢,使得CPU使用率100%
2、Netty中的解決思路:
對Selector()方法中的阻塞定時 select(timeMIllinois)操作的 次數進行統計,每完成一次select操作進行一次計數,若在循環週期內 發生N次空輪詢,如果N值大於BUG閾值(默認爲512),就進行空輪詢BUG處理。重建Selector,判斷是否是其他線程發起的重建請求,若不是則將原SocketChannel從舊的Selector上去除註冊,重新註冊到新的 Selector上,並將原來的Selector關閉。
源碼:已將部分代碼省略,全部代碼在io.netty.channel.nio.NioEventLoop類當中的select()方法中。
select方法分三個部分:
//第一部分:超時處理邏輯
//第二部分:定時阻塞select(timeMillins)
// 第三步: 解決空輪詢 BUG
long time = System.nanoTime();
//此處的邏輯就是: 當前時間 - 循環開始時間 >= 定時select的時間timeoutMillis,說明已經執行過一次阻塞select()
if (time - TimeUnit.MILLISECONDS.toNanos(timeoutMillis) >= currentTimeNanos) {
selectCnt = 1; // 說明發生過一次阻塞式輪詢
// 如果空輪詢的次數大於空輪詢次數閾值 SELECTOR_AUTO_REBUILD_THRESHOLD(512)
} else if (SELECTOR_AUTO_REBUILD_THRESHOLD > 0 && selectCnt >= SELECTOR_AUTO_REBUILD_THRESHOLD) {
/* setlctRebuildSelector():
* 1.首先創建一個新的Selecor
* 2.將舊的Selector上面的鍵及其一系列的信息放到新的selector上面。
/*
selector = this.selectRebuildSelector(selectCnt);
selectCnt = 1;
break;
}
currentTimeNanos = time;