在使用Netty的時(shí)候,不管是客戶端還是服務(wù)端應(yīng)用,都要配置EventLoopGroup,而常用的是NioEventLoopGroup,那來看一下NioEventLoopGroup在應(yīng)用中的初始化工作。
代碼
- 首先新建一個(gè)NioEventLoopGroup實(shí)例。新建的時(shí)候可以指定具體的線程數(shù),如果不傳入線程的數(shù)量,線程的數(shù)量則從系統(tǒng)屬性中獲取io.netty.eventLoopThreads,如果獲取不到那么啟動(dòng)的線程數(shù)量為系統(tǒng)的cpu核數(shù)的2倍。
// 實(shí)例化
EventLoopGroup bossGroup = new NioEventLoopGroup();
...
// 默認(rèn)線程數(shù)量
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
// 具體啟動(dòng)幾個(gè)線程
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
- 父類實(shí)例化的細(xì)節(jié),NioEventLoopGroup實(shí)例化的過程會(huì)不斷的實(shí)例化其父類,邏輯大都位于MultithreadEventExecutorGroup父類中,它的實(shí)例化過程如下:
- 新建ThreadPerTaskExecutor線程執(zhí)行器,默認(rèn)的ThreadFactory為DefaultThreadFactory(getClass())
- children未新建n個(gè)EventExecutor,如果是Nio的則為
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
- 將children作為參數(shù),新建EventExecutorChooser。
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTowEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
- 配置children也就是(EventExecutor)的terminationFuture監(jiān)聽器
- 設(shè)置只讀children
以上就完成了NioEventLoopGroup的創(chuàng)建工作。
- 我們?cè)倏纯礃?gòu)造NioEventLoopGroup的時(shí)候一些其他配置。
- ThreadPerTaskExecutor,其作用就是調(diào)用threadFactory新建一個(gè)線程,然后執(zhí)行。
public final class ThreadPerTaskExecutor implements Executor {
private final ThreadFactory threadFactory;
public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
if (threadFactory == null) {
throw new NullPointerException("threadFactory");
}
this.threadFactory = threadFactory;
}
@Override
public void execute(Runnable command) {
threadFactory.newThread(command).start();
}
}
- DefaultThreadFactory的新建線程,同時(shí)配置線程為daemon和線程優(yōu)先級(jí)。
@Override
public Thread newThread(Runnable r) {
Thread t = newThread(new DefaultRunnableDecorator(r), prefix + nextId.incrementAndGet());
try {
if (t.isDaemon()) {
if (!daemon) {
t.setDaemon(false);
}
} else {
if (daemon) {
t.setDaemon(true);
}
}
if (t.getPriority() != priority) {
t.setPriority(priority);
}
} catch (Exception ignored) {
// Doesn't matter even if failed to set.
}
return t;
}
protected Thread newThread(Runnable r, String name) {
return new FastThreadLocalThread(threadGroup, r, name);
}
- 線程選擇器,DefaultEventExecutorChooserFactory,內(nèi)部也比較明確,其主要就是從EventExecutor中按一定的規(guī)則選擇一個(gè)執(zhí)行線程。
- 最終的EventExecutor為NioEventLoop
最后
這次看了NioEventLoopGroup的構(gòu)建工作