NioEventLoop启动触发器
- 服务端启动绑定端口(第二篇文章已经介绍过)
- 新连接接入通过chooser绑定一个NioEventLoop(后面再介绍)
NioEventLoop启动
- 代码入口 ->doBind0方法中的execute(task)方法
- 创建线程 ->startThread() ->doStartThread()
- ThreadPreTaskExcutor.excute()创建线程
- thread=Thread.currentThread()保存当前线程
- NioEventLoop.run()启动
首先进入第二篇端口绑定所叙述的doBind0方法,看到了nioEventLoop执行execute方法,此处new Runable就是一个task,做一个绑定端口的事情
接着我们跟进execute方法选择SingleThreadEventExecutor,inEventLoop()会判断是否是本线程,由于还未创建,故这里会返回false,故接下来会执行startThread(),由于线程未启动,所以接下来执行doStartThread(),在这个方法里我们就会看到线程执行器创建NioEventLoop底层对应线程并保存,形成thread和NioEventLoop一对一的关系,然后启动NioEventLoop
![]()
![]()
![]()
![]()
![]()
![]()
NioEventLoop.Run()
- 代码入口 ->run()
- select检查是否有IO事件
- processSelectedKeys处理IO事件
- runAllTasks处理异步任务队列,就是前文的MpscQueue中的
进入run方法,选择NioEventLoop,就可以看到上述三个过程
![]()
select执行
- deadline以及任务穿插逻辑处理
- 阻塞式select
- 避免jdk空轮询的bug
首先选择未唤醒的,如果select次数为0则跳出进行,即非阻塞select,如果taskQueue(MpscQueue)有异步任务也会跳出,也是非阻塞select。紧接着后面的代码则是阻塞式select
![]()
![]()
![]()
紧接下面代码,如果未阻塞直接返回(即空轮询一次)则设置selectCnt = 1 若空轮询次数大于512则调用rebuildSelector()避免一直空轮询
![]()
processSelectedKeys执行
- selected keySet优化
- 调用processSelectedKeysOptimized处理IO事件
在前文NioEventLoop创建时调用openSelector()时候进行selected keySet优化 ,再在下图方法中传入优化后的selectedKey,再进行各种IO事件处理
![]()
![]()