Netty原始碼分析第2章(NioEventLoop)---->第3節: 初始化執行緒選擇器
第二章:NioEventLoop
第三節:初始化執行緒選擇器
回到上一小節的MultithreadEventExecutorGroup類的構造方法:
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) { //程式碼省略 if (executor == null) { //建立一個新的執行緒執行器(1) executor = new ThreadPerTaskExecutor(newDefaultThreadFactory()); } //構造NioEventLoop(2) children = new EventExecutor[nThreads]; for (int i = 0; i < nThreads; i ++) { boolean success = false; try { children[i] = newChild(executor, args); success= true; } catch (Exception e) { throw new IllegalStateException("failed to create a child event loop", e); } finally { //程式碼省略 } } //建立執行緒選擇器(3) chooser = chooserFactory.newChooser(children); //程式碼省略 }
我們看第三步, 建立執行緒選擇器:
chooser = chooserFactory.newChooser(children);
NioEventLoop都繫結一個chooser物件, 作為執行緒選擇器, 通過這個執行緒選擇器, 為每一個channel分配不同的執行緒
我們看到newChooser(children)傳入了NioEventLoop陣列, 我們跟到方法中去, 我們跟到了DefaultEventExecutorChooserFactory類中的newChooser方法:
public EventExecutorChooser newChooser(EventExecutor[] executors) { if (isPowerOfTwo(executors.length)) { return new PowerOfTowEventExecutorChooser(executors); } else { return new GenericEventExecutorChooser(executors); } }
這裡通過isPowerOfTwo(executors.length)判斷NioEventLoop的執行緒數是不是2的倍數, 然後根據判斷結果返回兩種選擇器物件, 這裡使用到java設計模式的策略模式
根據這兩個類的名字不難看出, 如果是2的倍數, 使用的是一種高效能的方式選擇執行緒, 如果不是2的倍數, 則使用一種比較普通的執行緒選擇方式
我們簡單跟進這兩種策略的選擇器物件中看一下, 首先看一下PowerOfTowEventExecutorChooser這個類:
private static final class PowerOfTowEventExecutorChooser implements EventExecutorChooser { private final AtomicInteger idx = new AtomicInteger(); private final EventExecutor[] executors; PowerOfTowEventExecutorChooser(EventExecutor[] executors) { this.executors = executors; } @Override public EventExecutor next() { return executors[idx.getAndIncrement() & executors.length - 1]; } }
這個類實現了執行緒選擇器的介面EventExecutorChooser, 構造方法中初始化了NioEventLoop執行緒陣列
重點關注下next()方法, next()方法就是選擇下一個執行緒的方法, 如果執行緒數是2的倍數, 這裡通過按位與進行計算, 所以效率極高
再看一下GenericEventExecutorChooser這個類:
private static final class GenericEventExecutorChooser implements EventExecutorChooser { private final AtomicInteger idx = new AtomicInteger(); private final EventExecutor[] executors; GenericEventExecutorChooser(EventExecutor[] executors) { this.executors = executors; } @Override public EventExecutor next() { return executors[Math.abs(idx.getAndIncrement() % executors.length)]; } }
這個類同樣實現了執行緒選擇器的介面EventExecutorChooser, 並在造方法中初始化了NioEventLoop執行緒陣列
再看這個類的next()方法, 如果執行緒數不是2的倍數, 則用絕對值和取模的這種效率一般的方式進行執行緒選擇
這樣, 我們就初始化了執行緒選擇器物件
回到上一小節的MultithreadEventExecutorGroup類的構造方法: