netty线程体系概览
netty的高并发能力很大程度上由它的线程模型决定的,netty定义了两种类型的线程:
I/O线程: EventLoop, EventLoopGroup。一个EventLoopGroup包含多个EventLoop, 每个Channel会被注册到一个,一个EventLoop中, 一个EventLoop可以包含多个Channel。Channel的Unsafe实例的方法必须要在EventLoop中执行(netty中明确指明的不需要在I/O线程中执行的几个方法除外,前面的章节中有详细的讲解)。
业务线程: EventExecutor, EventExecutorGroup。一个EventExecutorGroup包含多个EventExecutor。当用户向Channel的pipeline注册一个ChannelHandler时,可以指定一个EventExecutorGroup,这个ChannelHanndler的所有方法都会被放到EventExecutorGroup的中的一个EventExecutor中执行。 当用户没有为这个ChannelHandler明确指定EventExecutorGroup时,这个ChannelHandler会被放到Channel所属的EventLoop中执行。
 
为了能对netty的线程体系有一个整体的认识,笔者提供提供了一张线程的派生体系图供大家参考:

有上图我们可以得出这样几个有用的结论:

  1. netty的线程体系都是由EventExecutorGroup派生而来 而EventExecutorGroup派生自JDK的ScheduleExecutorService, 这表明netty的线程体系是对JDK Executor框架的扩展。
  2. netty核心的线程体系中,只提供了业务线程的最终实现: DefaultEventExecutorGroup, DefaultEvnetExecutor这两个是可以直接拿来用的。
  3. netty核心的线程体系中,为用户提供了I/O线程的框架: MultithreadEventLoopGroup, SingleThreadEventLoop, 具体I/O相关部分留给子类实现。
  4. 默认提供了用于创建线程的工厂类。
netty线性体系与JDK线程体系的对比
如果你熟悉java jdk, 就应该知道,jdk已经为开发者提供了一整套功能强大的基于多线程的Executor。那么问题来了: netty为什么要搞一套线程模型,有这个必要吗? 回答这个问题之前,我们先来对比一下两者有什么不同。
 
JDK的Executor框架

ThreadPoolExecutor是JDK Exector框架的核心实现,我们使用jdk的Executor框架,主要就是使用这个类,下面看一下这个类的实现原理

 
netty的EventExecutorGroup框架
MultithreadEventExecutorGroup是EventExecutorGroup框架的核心实现,这个类型的实现原理如下:

为了方便描述,先定义几个简称
ThreadPoolExecuto: TPE
MultithreadEventExecutorGroup: MEG
SingleThreadEventExecutor: STE
接下来,对比一下TPE和MEG
线程管理: TPE负责管理线程,根据传入的参数,运行过程中动态调节线程数,它也可以让线程一直保持在一个稳定的数量。MEG不负责管理线程,它只负责创建指定数量的STE, 每个STE只维护一个线程,保证有且只有一个线程。
任务排队: TPE维护一个所有线程共用的任务队列,所有线程都从同一队列中取任务。MEG没任务队列,它只负责把任务派发到一个STE, 默认的派发策略是轮询。每个STE维护一个私有的任务队列,STE会把任务放入私有的队列中排队,这队列只有STE维护的线程才能消费。
任务提交和执行: TPE把任务当成无关联的独立任务执行,不保证任务的执行顺序和execute的调用顺序一致, TPE认为任务的顺序不重要。MEG提交任务的方式有两种, (1)直接调用MEG的execute方法提交任务,这个方式,和TPE一样,不关心任务的执行顺序;(2)先从MEG中取出一个STE,然后调用STE的excute,这种方式任务的执行顺序和execute调用顺序一致。
性能: TPE使用共用的队列排队,在高并发环境下会导致BlockingQueue频繁的锁碰撞,进而导致大量线程切换开销,MEG中由于队列是只有一个线程消费,BlockingQueue锁碰撞机会比TPE小很多,线程切换开销也比TPE小很多,因此,可以得出结论,如果任务本身不会导致线程阻塞,MEG性能比TPE高, 否则MEG没有优势。
 
到这里已经可以回答前面提出的问题了: MEG把任务当成事件来看待,每个事件和特定的Channel关联(这一点由EventLoopGroup接口体现, 它定义了一个register(Channel channel)方法), 而一个特定Channel上触发的一系列事件,处理顺序和触发顺序必须要一致,如: 在Channel上先后触发了connect, read, close事件,如果业务上要求收到close事件后不再处理read事件, 如果执行先后顺序不能保证,很有可能执行不到read的业务。这种类似业务场景在基于TCP协议的服务器中很常见,这一点TPE不能支持,而MEG能够很好地支持这些对任务执行顺序有要求的场景。这就是netty要另外设计自己的线程模型的主要原因。
 
(注:为了能帮助读者更好地解本篇内容,接下来会补充一篇ThreadPoolExecutor代码解析的文章)

netty源码解解析(4.0)-4 线程模型-概览的更多相关文章

  1. netty源码解解析(4.0)-7 线程模型-IO线程EventLoopGroup和NIO实现(二)

    把NIO事件转换成对channel unsafe的调用或NioTask的调用 processSelectedKeys()方法是处理NIO事件的入口: private void processSelec ...

  2. netty源码解解析(4.0)-6 线程模型-IO线程EventLoopGroup和NIO实现(一)

    接口定义 io.netty.channel.EventLoopGroup extends EventExecutorGroup 方法 说明 ChannelFuture register(Channel ...

  3. netty源码解解析(4.0)-5 线程模型-EventExecutorGroup框架

    上一章讲了EventExecutorGroup的整体结构和原理,这一章我们来探究一下它的具体实现. EventExecutorGroup和EventExecutor接口 io.netty.util.c ...

  4. netty源码解解析(4.0)-11 Channel NIO实现-概览

      结构设计 Channel的NIO实现位于io.netty.channel.nio包和io.netty.channel.socket.nio包中,其中io.netty.channel.nio是抽象实 ...

  5. netty源码解解析(4.0)-10 ChannelPipleline的默认实现--事件传递及处理

    事件触发.传递.处理是DefaultChannelPipleline实现的另一个核心能力.在前面在章节中粗略地讲过了事件的处理流程,本章将会详细地分析其中的所有关键细节.这些关键点包括: 事件触发接口 ...

  6. netty源码解解析(4.0)-17 ChannelHandler: IdleStateHandler实现

    io.netty.handler.timeout.IdleStateHandler功能是监测Channel上read, write或者这两者的空闲状态.当Channel超过了指定的空闲时间时,这个Ha ...

  7. netty源码解解析(4.0)-18 ChannelHandler: codec--编解码框架

    编解码框架和一些常用的实现位于io.netty.handler.codec包中. 编解码框架包含两部分:Byte流和特定类型数据之间的编解码,也叫序列化和反序列化.不类型数据之间的转换. 下图是编解码 ...

  8. netty源码解解析(4.0)-20 ChannelHandler: 自己实现一个自定义协议的服务器和客户端

    本章不会直接分析Netty源码,而是通过使用Netty的能力实现一个自定义协议的服务器和客户端.通过这样的实践,可以更深刻地理解Netty的相关代码,同时可以了解,在设计实现自定义协议的过程中需要解决 ...

  9. netty源码解解析(4.0)-15 Channel NIO实现:写数据

    写数据是NIO Channel实现的另一个比较复杂的功能.每一个channel都有一个outboundBuffer,这是一个输出缓冲区.当调用channel的write方法写数据时,这个数据被一系列C ...

随机推荐

  1. hive sql 查询一张表的数据不在另一张表中

    有时,我们需要对比两张表的数据,找到在其中一张表,不在另一张表中的数据 hql 如下: SELECT * FROM (SELECT id FROM a WHERE dt = '2019-03-17' ...

  2. EBS获取并发程序Trace File

    http://blog.itpub.net/16832682/viewspace-1249765/ 最近因为项目上出现了PL/SQL性能的问题,因此需要对已经开发好的并发程序进行调优的工作.调优有个很 ...

  3. 在Delphi中处理word文档与数据库的互联 1

    在Delphi中处理word文档与数据库的互联 ---- 目前,Delphi被越来越多的人选中作为MIS系统开发中的前台工具.在以Delphi为前台,一些大型数据库为后台的MIS系统中,图形的处理不可 ...

  4. Android-Retrofit-2.0-Post与Get-请求有道词典翻译

    Retrofit-2.0版本后,内置已经集成了OKHttp,在使用Retrofit的时候 看似是Retrofit去网络请求的 实际上Retrofit只是封装,所以不要以为Retrofit是网络请求框架 ...

  5. Spring @Autowired注解用在集合上面,可以保持接口的所有实现类

    CourseService课程接口有2个子类,HistroyCourseServiceImpl和MathsCourseServiceImpl public interface CourseServic ...

  6. NODE-WEBKIT教程(5)NATIVE UI API 之FRAMELESS WINDOW

    node-webkit教程(5)Native UI API 之Frameless window 文/玄魂 原文链接:http://www.xuanhun521.com/Blog/2014/4/15/n ...

  7. Winform解决界面重绘闪烁的问题

    在窗体或用户控件中重写CreateParams protected override CreateParams CreateParams { get { CreateParams cp = base. ...

  8. .net图表之ECharts随笔03-热力地图

    基于01和02 要得到如图所示的热力地图(我从NuGet上下载的包没有heatmap.js文件,没法直接搞热力图,只好暂时先搞着地图.后面尽量搞一下),一般要设置四个参数——title.tooltip ...

  9. ASP.Net MVC OA项目笔记<二>

    1.1.0 创建数据层 1.1.1 CZBK.ItcastOA.IDAL 引用 CZBK.ItcastOA.Model 1.2.1 给IDAL添加一个接口IUserInfoDal 里面写增删改查分页的 ...

  10. win7 docker 挂载共享目录

    在 win7 下用 docker 不像 win10 那样方便,安装包都不一样. 在 win7 下共享一个目录的方法如下: 1. 先设置 win7 到 VirtualBox 中 docker 用的那个虚 ...