4.NioEventLoop的启动

101 阅读2分钟

NioEventLoop启动触发器

  1. 服务端启动绑定端口(第二篇文章已经介绍过)
  2. 新连接接入通过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 image.png image.png image.png image.png image.png image.png image.png

NioEventLoop.Run()

  • 代码入口 ->run()
  • select检查是否有IO事件
  • processSelectedKeys处理IO事件
  • runAllTasks处理异步任务队列,就是前文的MpscQueue中的

进入run方法,选择NioEventLoop,就可以看到上述三个过程 image.png image.png

select执行

  • deadline以及任务穿插逻辑处理
  • 阻塞式select
  • 避免jdk空轮询的bug

首先选择未唤醒的,如果select次数为0则跳出进行,即非阻塞select,如果taskQueue(MpscQueue)有异步任务也会跳出,也是非阻塞select。紧接着后面的代码则是阻塞式select image.png image.png image.png image.png 紧接下面代码,如果未阻塞直接返回(即空轮询一次)则设置selectCnt = 1 若空轮询次数大于512则调用rebuildSelector()避免一直空轮询 image.png image.png

processSelectedKeys执行

  • selected keySet优化
  • 调用processSelectedKeysOptimized处理IO事件

在前文NioEventLoop创建时调用openSelector()时候进行selected keySet优化 ,再在下图方法中传入优化后的selectedKey,再进行各种IO事件处理 image.png image.png image.png