Reactor的单线程和多线程
关于Reactor有一些地方想做下说明,因为看到网上说到这块内容的文章不是特别多,而提到这块的文章的一些用词可能会对一些同对Netty不是特别了解,或者正在学习Netty源码的同学造成一定困扰和误解,所以想在这里分享出来。这里有些理解可能和一些同学平时的认知不太相同。
如果本文所写有任何问题或者错误,欢迎指出讨论。
1.关于线程数
NioEventLoopGroup有多个构造方法,也有无参构造方法,。
无参构造方法将nThreads设置为0。
0就根据CPU核数决定线程数量。
如果不是0,就用你传入的nThreads来决定Reactor模型中负责处理请求的线程数量。
2.关于线程池
一般的文档中在说Netty的Reactor模式的时候,都说的是线程池。其实,从源码看来,如果用默认无参构造方式构造NioEventLoop,“线程池”这个称呼其实是不确切的,为什么这么说呢?我们继续跟代码,到MultithreadEventExecutorGroup类中:
这里可以看到,如果nThreads>0,说明是Reactor的多线程模式,这里children数组大小就是nThreads。
这里executor是null,所以用的是ThreadPerTaskExecutor,它是JDK的Executor接口的实现:
可以看到,其实就是用ThreadFactory新建一个线程而已。那么对于容量为nThreads的children数组来说,就是创建了这些个线程来执行任务而已,并没有真正使用jdk的线程池模型。
然后在调用newChild方法初始化每个数组元素的时候,以NioEventLoopGroup举例,它将该executor封装在构造的NioEventLoop中,构造的NioEventLoop的个数也和数组大小相同。
当然这么做其实也没问题,因为这些线程执行的都是for(;;)这种死循环任务,所以也不存在回收或者复用之类的动作。
只是这里所说线程池的“池”,具象化是一个Executor数组,而不是JDK的线程池。
3.给任务分配线程
因为不是所谓的jdk的线程池,所以这里也不能像使用jdk线程池那样,来了任务直接Executor.execute就万事大吉了,如上面所说,这里的线程池其实是一个数组,所以我们要从数组中选择一个ThreadPerTaskExecutor来执行任务,选择的类是EventExecutorChooser,具体实现有GenericEventExecutorChooser和PowerOfTwoEventExecutorChooser。
总而言之,就是想说一下这里的线程池的含义,希望其他看源码的小伙伴在看到这里的时候,不会一头雾水到处找jdk的线程池,却发现找到的和自己设想的不太一样。
后面还会放一些个人在学习Netty源码的时候的一些类似的总结和见解,望指正,探讨,一起学习,一起成长。