开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情
我正在参与掘金会员专属活动-源码共读第一期,点击参与
分析 io.netty.channel.nio.NioEventLoop#run做了哪些事情
一、NioEventLoop概述
NioEventLoop做为Netty线程模型的核心部分,从本质上讲是一个事件循环执行器,每个NioEventLoop都会绑定一个对应的线程通过一个for(;;)循环来处理与 Channel 相关的 IO 操作, 包括 调用 select 等待就绪的 IO 事件、读写数据与数据的处理等;其次作为任务队列, 执行 taskQueue 中的任务, 例如eventLoop.schedule 提交的定时任务也是这个线程执行的。而NioEventLoopGroup顾名思义,它是维护了一组这样的事件循环器,这也是Netty基于Reactor模式的具体设计体现。
类层次结构如下
通过构造函数传入线程数量
NioEventLoopGroup最终的构造函数中包含以下元素
nThreads:传入的线程数
executor:线程执行器Executor接口,默认为空
selectorProvider:用于创建Selector的SelectorProvider
selectStrategyFactory: 策略工厂
RejectedExecutionHandlers.reject():自定义线程拒绝策略
父类会根据nThreads确定初始化线程数量,为0则会以当前核心线程数*2作为默认线程数量
接下来在MultithreadEventExecutorGroup的构造函数中我们会根据传入的线程数,去初始化和创建一组NioEventLoop
下面在MultithreadEventExecutorGroup构造函数中主要完成以下几个功能:
1、初始化ThreadPerTaskExecutor线程执行器,并传入一个线程创建工厂,用于NioEventLoop对应线程的创建
2、根据传入的线程数,初始化一个EventExecutor数组,用于放置创建的NioEventLoop对象
3、循环数组,通过newChild方法创建NioEventLoop对象。
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) {
// 创建线程工厂,netty根据需要指定了线程的命名方式、优先级、是否是守护线程等属性
// 该线程池没有任何队列,提交任务后,创建任何县城类型都是FastThreadLocalRunnable,立即start
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
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
继续跟踪newChild(),看到他返回一个EventLoop对象
通过上面的代码,初始化NioEventLoop主要完成几个功能
1.保存线程执行器ThreadPerTaskExecutor 2.创建一个selector 3.基于LinkedBlockingQueue创建一个taskQueue任务队列,用于保存要执行的任务