第一次尝试在知乎写技术文章,略紧张,本文大概1000字,阅读时间大约5分钟,前面使用了多篇文章,透彻总结拆解了Netty的线程图像,或者说线程模型,下面对Netty的线程池做一个小的总结。不妨带着问题阅读:
1、Netty有多少类线程池,它们的区别和使用场景都是什么?
2、Netty的线程池和JDK的线程池有什么区别?
一般的,Netty里常用的线程池有如下几种:
经过前面的分析,知道Netty实现了自己的线程池——EventLoopGroup。其中最最常用的就是大家都知道的NioEventLoopGroup,在非阻塞模式的编码中,基本都是用它来实现Reactor模型。其实更清晰的说法是Netty在自己的线程封装类——NioEventLoop中封装了JDK的线程实例Thread,I/O多路复用器以及异步任务队列,实现了高性能的线程模型。使用如下:
EventLoopGroup workerGroup = new NioEventLoopGroup();
另外,上一篇文章刚刚总结了GlobalEventExecutor.INSTANCE,我想就不必多说,严格来说它不算线程池,但是理解为只有一个线程的特殊的线程池也未尝不可。
除了以上线程池,Netty还提供了一种非I/O线程池——DefaultEventExecutorGroup,它的用法和I/O线程池一样,如下:
EventExecutorGroup businessGroup =
new DefaultEventExecutorGroup(16); // 业务线程池
即:
1、NioEventLoopGroup线程池内部是NioEventLoop,它可以理解为是I/O线程,它内部聚合了Java的Thread,以及JDK的I/O多路复用器,实现了事件循环机制,侧重于处理网络I/O相关的各种操作
2、DefaultEventExecutorGroup线程池内部是DefaultEventExecutor,它可以理解为是非I/O线程,内部聚合了Java的Thread,但没有I/O多路复用器,侧重于处理耗时业务逻辑(非I/O操作)
下面重点看这个DefaultEventExecutor的实现,如下类定义:
注释写到:默认的Netty线程执行器会串行的执行提交到它的异步任务。
下面是Netty的线程模型完整类图,包括了线程和线程池,最上面是继承的JDK的线程池相关接口,包括定时任务执行器,左下角是Netty的线程池,右下角是线程:
作为对比,回忆NioEventLoop的创建过程,它会在I/O线程池NioEventLoopGroup中,使用newChild方法创建:
同理,DefaultEventExecutor的创建过程如出一辙,也会在非I/O线程池DefaultEventExecutorGroup中,使用newChild方法创建:
两类线程(池)的区别:
1、I/O线程池里的线程封装实例Thread会绑定I/O多路复用器,以及配套的NIO的属性,非I/O线程池的线程只封装Thread,类似于JDK原生的线程,很干净。
2、非I/O线程池的线程执行器的执行原理和I/O线程池的线程执行器没什么区别,都可以统称为Netty线程,而且它们都消除了锁竞争。即每个Channel只会绑定一个不变的Netty线程,而一个Netty线程可以绑定多个Channel,期间每个Channel上的各种handler的逻辑执行都是串行无锁的。如下是DefaultEventExecutor的run:
逻辑就是当前一个非I/O线程在不断的执行其异步任务队列——MPSCQ里的任务。即不论是I/O线程还是非I/O线程,在执行任务时,都是下面这样的图像:
以上,总结完了Netty的几类线程池,对于非I/O线程池来说,最常见的用法可以参考文章:Netty耗时的业务逻辑应该写在哪儿,有什么注意事项?
下面看看它们和JDK线程池的区别
两者比起来,Netty线程池里的线程全部消除了对锁的竞争,而JDK的线程池没有这种设计,JDK线程池的线程会处理同一个阻塞队列。比如LinkedBlockingQueue,可能产生锁竞争。如下(图来源于网络,侵删):
虽然LinkedBlockingQueue通过读写锁来提升性能,但是当业务线程数和写操作比较多时,锁竞争对性能的影响还是比较大的。如果采用自定义线程池,那么优化方向就是锁消除,也可以使用Disruptor或者使用Channel Id与业务线程池中的某个业务进行绑定。当然最好是直接使用Netty默认实现的业务线程池。并且还可以搭配操作系统层面的CPU亲和特性,来给某个线程指定CPU内核,使其尽可能不发生切换。
小结:
以上简单总结了Netty的几大类常用,常见的线程池,并且分析了它们在不同场景下的用法,还对比了它们和JDK线程池的区别,需要掌握用法,更重要的是掌握线程池的多种设计思路,和多线程代码的高性能的编写技巧。