其实在将这一节以前,咱们来分析一个东西,方便下面的工做好开展。算法
打开启动类,最开始的时候建立了一个NioEventLoopGroup 事件循环组,咱们来跟一下这个。数组
这里bossGroup, 我传入了一个线程, workerGroup 没有入参,默认0, 也就是说父级我用一个线程来处理客户端的接入, 多个线程来处理客户端的读写操做安全
经过一连串的构造方法进入到异步
executor 是 null , selectorProvider 用来建立一个多路复用器, 最后一个参数传入了 一个多路复用器的一个策略, 这个策略咱们后面会讲到ide
紧接着又传入了一个拒绝策略, 因为 NioEventLoopGroup 继承了 MultithreadEventLoopGroup,因此进入 MultithreadEventLoopGroup 的构造方法oop
这里的判断, bossGroup 传入了 1 ,因此nThreads = 1; workerGroup 没有入参,默认是0 ,因此这里到了一个判断默认线程数的地方。性能
就是这了, NettyRuntime.availableProcessors() * 2 表明 CPU核心数 * 2(处理器超线程数) * 2的值 或 CPU数 * 2的值 spa
在cmd命令中输入“wmic”,而后在出现的新窗口中输入“cpu get *”。
NumberOfCores:表示CPU核心数
NumberOfLogicalProcessors:表示CPU线程数线程
因此我这里是 CPU核心数 是 2 , CPU 线程数 是 4 , 因此个人 NettyRuntime.availableProcessors() * 2 = 8, 而后这里Math.max(1,8) 取大的 就是 8 了blog
因此个人 workerGroup 线程数 是 8
好了,咱们继续跟进去
这里建立了一个线程工厂,主要是为线程设置名字、是否守护进程、线程的优先级等等。而后建立一个任务执行器,把线程工厂传进去赋给成员变量
这个executor 后面在每一个 事件执行器 建立子线程处理task来用
接下来建立一个长度是nThreads的 EventExecutor[] ,对于 子事件循环组来讲,这里实际上是建立了一个长度为8 的NioEventLoop的数组, 即 EventExecutor[] children = new NioEventLoop[8]
这个地方我纠结了一下,由于我语文太差了,我决定画个图来展现一下, 虽然我美术也很差。
你们看下这个代码层级结构, 其实就很显而易见了,这里我要说一下,SingleThreadEventExecutor 中有一个thread成员变量,说明每一个都只有一个线程来处理,而且含有任务队列和任务的执行器。
另外每个NioEventLoop都含有一个selector 多路复用器 。
继续看,这里经过默认的选择工厂来建立一个选择器。
跟进去,咱们看到下面的这段代码,不得不感叹Netty真的已经把性能发挥到了极致,能用位运算的毫不会用数学计算法,因此这里对选择器进行了区分
看这个判断方法,意思是 若是是 2的次方 ,那么建立一个 PowerOfTwoEventExecutorChooser 选择器
我特地去验证了一个这个算法
结果是:
好了,讲到这里咱们能够从新开始讲注册了,仍然进入 initAndRegister()方法
config().group() 这个获取到的 是 ServerBootStrap.group(), 那么也就是取到了 父级的事件循环组 也就是bossGroup
根据我上上图的分析,那么注册方法进入的确定是 MultithreadEventLoopGroup
这里有一个next()方法,用来选择一个NioEventLoop。因为我这里是1个线程的数组,因此进入
所以,对于bossGroup来讲,就是 0 & 0 = 0 1 & 0 = 0 2 & 0 = 0 .....
对于workerGroup来讲,就是 0 & 7 = 0 1 & 7 = 1 2 & 7 = 2 .... 8 & 7 = 0 9 & 7 = 1 ....
因此这里实际上是一个轮询的算法。
ok, 看到这里咱们猜想是 从 new NioEventLoop[1] 中轮询一个 NioEventLoop, 而后把channel注册到上面的多路复用器上。
继续看, 根据那个流程图,能够推断出是进入到 SingleThreadEventLoop
接着传入了一个 DefaultChannelPromise ,用来作注册结果的异步通知的。传入了channel 和 当前的这个 SingleThreadEventLoop ,固然具体怎么异步通知的,咱们后面会讲到
继续看
这里把刚刚选择出来的 NioEventLoop 赋给 Channel 的 eventLoop 的成员变量, 这里也就意味着 ,这个NioEventLoop 也将一直伴随 这个channel 的全部的读写操做, 由于经过上面的那个流程图代表了 一个NioEventLoop 上面只有一个Thread , 那么也能够得出 一个Channel 整个周期 内全部的读写操做,所有由同一个Thread来完成, 这也就说明了为何Netty没有线程安全问题,固然随着后面的讲解,你将会对这个地方理解的更加的深入。
好了,注册的内容咱们下一节接着说。