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. Ubuntu12.04搭建自有源

    其实,这个工作比较简单,主要两步:apt-mirror和apache.(这里的系统是ubuntu12.04) 1.apt-mirror 1.1 安装 一如既往地简单,直接sudo apt-get in ...

  2. Android-Java-面向对象的代码例子

    需求一:用手机打电话,发短信,看视频,听音乐,用面向对象思想实现: package android.java.oop01; /** * 1.既然是面向/面对 --> 对象 就要把 (用手机打电话 ...

  3. [转载]DevOps发展的四个重要阶段

    DevOps是敏捷开发的延续,它将敏捷的精神延伸至IT运营(IT Operation)阶段.敏捷开发的主要目的是响应变化,快速交付价值.以2001年的敏捷宣言发布这个里程碑为起点,开始几年内企业主要在 ...

  4. 未能加载文件或程序集,PublicKeyToken=“**********”,或它的某一个依赖项。强名称验证失败。

    就是这种错误.这种错误怎么办? 以下步骤: (以上图dll为例) 1.看项目的Debug文件夹下是否有以下三个文件 2.看项目的.csproj文件下引用的报错dll的publickeytoken和版本 ...

  5. MVC框架json数据展示程序(第一版)

    模型原型:服务器的配置和运行状态信息. 设计要求:Json格式数据解析后,判断配置信息是否是新数据或者是否更新.如是新数据,则直接添加到数据库:若是数据更新,则更新数据库配置信息并更新运行状态信息:都 ...

  6. 【转】 js数组 Array 交集 并集 差集 去重

    原文:http://blog.csdn.net/ma_jiang/article/details/52672762 最劲项目需要用到js数组去重和交集的一些运算,我的数组元素个数可能到达1000以上, ...

  7. [leetcode.com]算法题目 - Triangle

    Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent n ...

  8. CF1146H Satanic Panic

    题目传送门 Description 给定二维平面内\(n\)个点\((n\leq 300)\),求能组成五角星(不要求正五角星)的五元组个数. Solution 一道小清新的寄蒜几盒计算几何题,代码不 ...

  9. Swift 里 Set(二)概览

    类图  Set 是一个结构体,持有另一个结构体_Variant. 最终所有的元素存储在一个叫做__RawSetStorage的类里. 内存布局  结构体分配在栈上,和__RawSetStorage ...

  10. job任务执行流程与分区机制

    job任务执行流程    1.run job阶段        ①收集整个job的环境信息(比如通过conf设定的参数,还有mapperClass,reducerClass,以及输出kv类型)     ...