NioEventLoopGroup初始化

本文是我对Netty的NioEventLoopGroup及NioEventLoop初始化工作的源码阅读笔记, 如下图,是Netty的Reactor线程模型图,本文描述NioEventLoopGroup就是我在图中标红的MainReactor的组件,全篇围绕它的初始化,难免地方理解的不正确,欢迎留言

Reactor线程模型图

在Nio网络编程模型的图示是下面那张图, 单条Thread全职执行一个Selector,首先是服务端在启动的时候,会把代表服务端的ServerSockerChannel注册进Selector,且感兴趣的事件是Accept, 一旦有客户端请求建立连接,ServerSockerChannel的accept事件就会被Selector感知到,进行下一步处理

NIO模型图

对NioEventLoopGroup最感性的认识,是在一定程度上,它其实是对上图组件的封装,那么封装了哪些部分呢?

对Thread的封装

NioEventLoopGroup维护的是事件循环,EventLoop, 在Netty的主从Reactor线程模型中,两个事件循环组其实也是线程组,因为每一个EventLoop在他的整个生命周期中都始终和一条线程唯一绑定,EventLoop的线程使用的是它自己封装的FastThreadLocalThread, 这条线程使得EventLoop有了处理事件的能力

对Selector的封装

NioEventLoopGroup维护的是事件循环,EventLoop,同样维护着属于自己的Selector选择器,这个选择器使得EventLoop拥有了轮询绑定在自己身上的Channel的能力. 并且Netty对JDK原生的选择器做出了升级,使用自定义的数组替换了原生Selector的HashSet集合SelectedKeys,使得时间的复杂度在任何时刻都是O1

现在看,每一个EventLoop都是一个工作单元, 它的声明周期是怎样的? 下面就开始正式的阅读源码

继承体系图

上图是一个简化了体系图,,慢慢撸出他们的关系

流程图

这个图使我们下面源码的流程图, 完成NioEventLoopGroup的初始化

入口:

EventLoopGroup bossGroup = new NioEventLoopGroup(1);

经过基层this()构造方法的调用,我们来到它的这个构造方法, 它调用了父类的构造方法,带上了默认的select策略,已经拒绝执行任务的handler

public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory) { //todo 0 null 根据系统选出 nioXXXprovider 默认的选择策略 // todo 调用父类的构造方法 MultithreadEventLoopGroup 多线程的事件循环组 super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()); }

接着进入super() , 进入MultiThreadEventLoopGroup 多线程事件循环组, 它干了键大事, 初始化了NioEventLoopGroup线程的数量,注意,是数量, 源码在下面: 当然,我们一般会把BossGroup的线程数量设置为1

// todo 当MultithreadEventLoopGroup被加载进 JVM就会执行, 对 DEFAULT_EVENT_LOOP_THREADS进行初始化 static { // todo max方法取最大值, // todo SystemPropertyUtil.getInt,这是个系统辅助类, 如果系统中有 io.netty.eventLoopThreads,就取它, 没有的话,去后面的值 // todo NettyRuntime.availableProcessors() 是当前的 系统的核数*2 , 在我的电脑上 2*2*2=8条线程 DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt( "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2)); if (logger.isDebugEnabled()) { logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS); } } /** * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...) */ // todo 接着 使用父类的构造方法, nThreads= DEFAULT_EVENT_LOOP_THREADS // todo Object... args 是 selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()的简写 protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) { super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args); }

接着进入它的Supper() 来到了它的父类的构造方法,MultiThreadEventLoopExcutorGroup的构造方法, 这个类是至关重要的类,它做了大量的初始化工作, 总体上看:

首先: 根据上一步确定的它可以拥有的线程数,循环创建并初始化一个EventExecutor[] 这个数组其实就是盛放EventLoop的数组, 当这个for循环结束后,实际上NioEventLoopGroup就添加完成了EventLoop

初始化选择器工厂, 这个工厂的作用是, 当出现新的IO事件需要处理时,通过工厂的轮询算法,从NioEventLoopGroup中选取一个NioEventLoop处理

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwwsd.html