NioEventLoop

三个问题

1.默认情况下,Netty服务端起多少线程?何时启动?

答: 2*CPU核数个线程。在调用execute方法时,会判断当前是否在本线程,如果是在本线程,说明线程已经启动;如果是在web线程,调用execute方法,首先会调用startThread方法,这个方法首先会判断当前线程是否启动,如果没有启动就启动该线程。

 

2.Netty是如何解决jdk空轮询bug的?

 Netty是通过计数的方式判断的。如果当前阻塞的一个select操作实际上并没有花那么长时间,那么这一次就可能触发了空轮询bug,默认情况下如果这个现象达到512次,然后就重建一个selector,把之前selector上面所有的key重新移交到新的selector,通过这种方式来巧妙的避免了空轮询bug。

 

3.Netty如何保证异步串行无锁化?

常见的场景就是在拿到客户端的Channel,而不需要对这个Channel进行同步就直接可以多线程并发读写,而另外一个就是Channel Header里面所有的操作都是线程安全的,不需要进行同步。Netty在所有的web线程去调用EventLoop或者Channel里方法的时候,通过inEventLoop这个方法来判断得出是web线程,这种情况下就把所有的操作封装成一个task,丢到MpscQueue里面,然后在NioEventLoop 执行逻辑的第三个过程,这些task会被依次执行。

 

 NioEventLoop

(1)NioEventLoop创建

(2)NioEventLoop启动

(3)NioEventLoop执行逻辑

 

(1)NioEventLoop创建

new NioEventLoopGroup()[线程组,默认2*cpu]

       new ThreadPerTaskExecutor()[线程创建器]

       for(){newChid()}[构造NioEventLoop对象数组]

       chooserFactory.newChooser()[线程选择器]

(a)ThreadPerTaskExecutor()

  • 每次执行任务都会创建一个任务实体
  • NioEventLoop线程命名规则nioEventLoop-1-xx

(b)newChid()

  • 保存线程执行器ThreadPerTaskExecutor
  • 创建一个MpscQueue
  • 创建一个selector

(c)newChooser()

  • isPowerOfTwo()[判断是否是2的幂,如2、4、8、16]

    PowerOfTwoEventExecutorChooser[是2的幂,优化]

      index++&(length-1)//也可以实现从0到最后一个,再从0到最后一个的循环操作

    GenericEventExecutorChooser[普通]

      abs(index++%length)//从0到最后一个,再从0到最后一个循环

 

  • index++&(length-1)运行过程:

index                       111010

              &

executors.length-1        1111

result                      1010

原因:java底层中  &操作比%操作更快

(2)NioEventLoop启动

  • 服务端启动绑定本地端口
  • 新连接接入通过chooser绑定一个NioEventLoop

bind()—>execute(task)[入口]

  startThread()—>doStartThread()[创建线程]

    ThreadPerTaskExecutor.execute()

      thread=Thread.currentThread()

      NioEventLoop.run()[启动]  

(3)NioEventLoop执行逻辑

SingleThreadEventExecutor.this.run()

  NioEventLoop.run()—>for(;;)

    select()[检查是否有io事件]

    processSelectedKeys()[处理从上一过程中轮询出来的io事件]

    runAllTasks()[处理异步任务队列]

(a)检测IO事件

select()方法执行逻辑

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

(b)处理IO事件

processSelectedKeys()方法执行逻辑

  • selected keySet优化
  • processSelectedKeysOptimized()

(c)reactor线程任务的执行

runAllTasks()方法执行逻辑

  • task的分类和添加
  • 任务的聚合:将定时任务队列里的task聚合到普通的taskQueue里面
  • 任务的执行

    

 

posted @ 2018-07-22 20:36  chan_ai_chao  阅读(177)  评论(0编辑  收藏  举报