EchoServer流程-2.group的初始化
1.EventLoopGroup
在启动Netty的Server端时,先初始化了两个EventLoopGroup,分别为bossGroup和workerGroup:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
io.netty.channel.EventLoopGroup是一个接口类型,继承了io.netty.concurrent.EventExecutorGroup(也是一个接口),EventExecutorGroup继承的接口已经不属于netty,属于原生的JDK的并发工具。
具体的实现类是NioEventLoopGroup
2.NioEventLoopGroup
如果使用无参数构造方法,在NioEventLoopGroup.java中,最终会使用到如下的构造方法:
/* NioEventLoopGroup.class */
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
2.MultithreadEventLoopGroup
其中会自行生成线程数、执行器、Selector等参数(这个之后再分析),然后调MultithreadEventLoopGroup的构造方法(将线程数设置为物理核心数的二倍):
/* MultithreadEventLoopGroup.class */
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
MultithreadEventExecutorGroup的构造方法。这个方法是最终进行了真正处理的方法,如下为重点逻辑:
执行器,属于JDK的并发
/* ThreadPerTaskExecutor.class */
// ThreadPerTaskExecutor是一个简单的线程
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
使用循环将children填补完全,并且处理失败
/* MultithreadEventLoopGroup.class */
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
// create EventExecutor
children[i] = newChild(executor, args)
......
}
3.NioEventLoopGroup
其中,newChild()方法的实现类为NioEventLoopGroup,但是在MultithreadEventLoopGroup中被定义为abstract方法。
/* NioEventLoopGroup.class */
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
// 检查参数长度,使用工厂模式
EventLoopTaskQueueFactory queueFactory = args.length == 4 ? (EventLoopTaskQueueFactory) args[3] : null;
// 返回值的类型为NioEventLoop
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2], queueFactory);
}
此处的NioEventLoop为新的类,查看继承关系图:
4.NioEventLoop
在NioEventLoop的构造方法中,可以追溯到AbstractEventExecutor的构造方法,AbstractEventExecutor记录了自己所属的EventExecutorGroup,并且在构造方法中填充:
/* AbstractEventExecutor.class */
protected AbstractEventExecutor(EventExecutorGroup parent) {
this.parent = parent;
}
之后的工作为SingleThreadEventExecutor的构造方法,其中SingleThreadEventExecutor需要更多的类成员。SingleThreadEventExecutor类中有很多负责各种执行和同步的类成员,这里不全部的详细说明。这里摘抄一段此构造方法的注释:
/**
* Create a new instance
*
* @param parent the {@link EventExecutorGroup} which is the parent of this instance and belongs to it
* @param executor the {@link Executor} which will be used for executing
* @param addTaskWakesUp {@code true} if and only if invocation of {@link #addTask(Runnable)} will wake up the
* executor thread
* @param maxPendingTasks the maximum number of pending tasks before new tasks will be rejected.
* @param rejectedHandler the {@link RejectedExecutionHandler} to use.
*/
SingleThreadEventExecutor执行完毕后,SingleThreadEventLoop另外加入一个tailTasks,用于存储task。
super(parent, executor, addTaskWakesUp, taskQueue, rejectedExecutionHandler);
tailTasks = ObjectUtil.checkNotNull(tailTaskQueue, "tailTaskQueue");
此时,回到NioEventLoop的构造方法,完成selector的填充(selector作为java nio的核心概念,这里先不进行详细说明)。
到此,完成了一个EventExecutor的生成(实际上是生成了一个NioEventLoop实例)
chooser是一个用于实现选择策略的类,比如默认构造器DefaultEventExecutorChooserFactory实现了简单的RR(轮询),这个chooser的主要的作用是从EventExecutor中返回一个next()。在实现类中就是从children数组中挑一个成员出来。
遍历每一个children的元素,添加一个terminationListener,然后包装成一个不可修改的Set集合readonlyChildren。
到此,完成了NioEventLoopGroup的构造方法,EchoServer中的两个group初始化完毕。
5.总结
EventLoopGroup是netty中用来监听并处理Event的实体,可以理解为封装后的线程池。
EventLoopGroup的成员变量中,管理了许多EventLoop,它们是用来处理事件的,比如默认的
SingleThreadEventLoop一个真正处理事件的线程。
关于eventloop可以参考这篇文章:https://blog.csdn.net/thinking_fioa/article/details/81952066