針對(duì)Netty的Reactor線程模型盼忌,從理論上來(lái)看確實(shí)設(shè)計(jì)的比較巧妙积糯,將接受連接請(qǐng)求和處理讀寫(xiě)事件分開(kāi),避免了一直阻塞的問(wèn)題谦纱】闯桑看完這些,一直比較好奇的是Netty在代碼中是如何實(shí)現(xiàn)的跨嘉,于是開(kāi)始研究Netty的源碼川慌,今天就先研究下NioEventLoopGroup這個(gè)類的具體實(shí)現(xiàn)過(guò)程。
public void start() throws InterruptedException {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1); #1
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
}
第一步首先初始化NioEventLoopGroup這個(gè)類祠乃,我們首先看下這個(gè)初始化操作做了些什么事情窘游,具體的初始化操作主要在MultithreadEventExecutorGroup這個(gè)父類中完成。
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
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) {
// TODO: Think about if this is a good exception type
} finally {
}
chooser = chooserFactory.newChooser(children);
}
在這個(gè)類中跳纳,首先判斷nThreads這個(gè)變量的值,這個(gè)值表示的是線程的數(shù)量贪嫂,如果在NioEventLoopGroup初始化時(shí)沒(méi)有傳入這個(gè)值寺庄,默認(rèn)為cpu核數(shù)*2。
excutor參數(shù)默認(rèn)為null,初始化時(shí)主要是初始化了ThreadPerTaskExecutor 這個(gè)類中的threadFactory參數(shù)斗塘,從名稱上也能看到這是個(gè)創(chuàng)建線程的工廠類赢织。
children是個(gè)數(shù)組于置,數(shù)組的初始化是通過(guò)newChild這個(gè)方法完成贞岭,NioEventLoopGroup實(shí)現(xiàn)了此方法,下面具體看下這個(gè)方法的具體實(shí)現(xiàn)過(guò)程话速。
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
從newChild這個(gè)方法的實(shí)現(xiàn)上就可以看到泊交,這個(gè)方法返回了一個(gè)新創(chuàng)建的NioEventLoop對(duì)象柱查,所以children這個(gè)數(shù)組中存儲(chǔ)的是NioEventLoop對(duì)象。NioEventLoop對(duì)象的初始化過(guò)程不再往下跟了研乒,有需要再跟下酵紫。
初始化children數(shù)組后奖地,通過(guò)DefaultEventExecutorChooserFactory工廠創(chuàng)建了一個(gè)EventExecutorChooser對(duì)象,這個(gè)對(duì)象非常重要仰楚,主要作用就是為channel分配到哪個(gè)NioEventLoop上確定分配策略犬庇,下面看下具體實(shí)現(xiàn)。
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
}
從上面這個(gè)工廠類中可以看到捂襟,此工廠類是根據(jù)executors這個(gè)數(shù)組的長(zhǎng)度是否是2的冪次方葬荷,選擇具體的EventExecutorChooser實(shí)現(xiàn)類,這兩個(gè)子類的具體實(shí)現(xiàn)如下:
private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
}
private static final class GenericEventExecutorChooser implements EventExecutorChooser {
@Override
public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
}
從上面的代碼就可以清楚的看到举反,主要是通過(guò)next方法從數(shù)組中選擇一個(gè)NioEventLoop對(duì)象火鼻,后面會(huì)詳細(xì)講解這個(gè)next方法怎么使用的雕崩。至此,NioEventLoopGroup這個(gè)類的源碼重要的部分就分析完了蛾默,總結(jié)一下:
- 一個(gè)NioEventLoopGroup中會(huì)管理多個(gè)NioEventLoop對(duì)象捉貌,相當(dāng)于線程池,NioEventLoop相當(dāng)于線程牧挣。
- NioEventLoopGroup中會(huì)初始化EventExecutorChooser對(duì)象醒陆,確定這個(gè)NioEventLoopGroup中分配NioEventLoop對(duì)象的策略。