文章目录
NioEventLoop创建

NioEventLoopGroup的构造函数
默认传入nThreads为0,一直跟踪构造函数,直到最高层
先来看ThreadPerTaskExecutor
这个线程创建器有两个知识点
1.每次执行任务都会创建一个线程实体
2.NioEventLoop线程命名规则nioEventLoop-x-xx
先来看第一点
找到创建线程创建器的地方(上面大纲中已经讲到)
点进去构造函数看一下
通过传入一个线程工厂来构造这个线程创建器,每次执行任务都是通过线程工厂创建一个线程执行提交的任务
第二点命名规则是如何在代码中体现的
跟踪ThreadFactory
toPoolName到底做了什么,打开这个方法
当类型的长度是0或者1的时候都是比较特殊的情况,重点关注长度大于1的时候,
逻辑是:
如果该类型的名称第0位是小写而且第1位是大写的话,那么把第0为转为小写,并且连接上第一位开始往后所有的字符。其实就是把第一位数字转为小写
这样传入的是NioEventLoop,转化后就成了nioEventLoop
知道了toPoolName方法后,继续跟踪构造函数
点进去:
继续跟踪构造
到这里,名称已经成了"nioEventLoop-1-"
当线程工厂创建线程的时候,会调用newThread方法
newThread:
看到这里,name就构建完成了 eg:nioEventLoop-1-1
需要说明的是这里的newThread并不是底层的原生线程,而且经过包装处理的,这里作了解,以后详细剖析(大概是把ThreadLocal做了优化,自己包装了一个ThreadLocalMap)
newChild()方法创建NioEventLoop
newChild方法做了什么事情:
从newChild方法进入
这块看的是NioEventLoop的实现方法
跟踪NioEventLoop的构造函数
通过openSelector()方法对selector赋值,也就是创建了一个Selector
继续跟踪super父类,看看父类构造中做了什么事情
连续两次跟踪父类,可以看到
第一个框通过外部传参保存了线程执行器(线程创建器ThreadPerTaskExecutor)
第二个框创建了一个MpscQueue队列,点进方法看一下:
这里看的是NIoEventLoop的实现方法
这个队列的作用是:外部线程把任务扔进来,保存到任务队列中,这个队列
就是MpscQueue,NioEventLoop直接从队列中执行任务。
创建线程选择器chooserFactory.newChooser()
接上面的三大步骤的最后一步,关于创建线程选择器的代码块
先来说一下线程选择器的工作机制是怎样的
如果NioEventLoop的数量不是2的幂次方, 2的幂次方如:2,4,8,16
那么每次有一个新连接,就会按顺序进行分配,分配一个NioEventLoop后,下标加1,如果到最后一个N
那么就重头开始,再来一遍
如果NioEventLoop的数量是2的幂次方,那么直接将该连接的次序与NioEventLoop的长度-1,这块内容在HashMap中也应用到了:将
下标映射到数组上。
即: xxxx & NioEventLoop.length-1
用结构图来描述这两个过程:
看一下源码里面是如何体现这两个过程的
这里的isPowerOfTwo()就是判断是否是2的幂
先点开第一个PowerOfTowEventExecutorChooser
点开后看next方法,可以看到和上面描述的一样
再点开第二个GenericEventExecutorChooser
Netty为什么要这样优化呢?因为在执行过程中,与运算的执行效率要大于取模运算 即:& > %