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. hdu 5072 两两(不)互质个数逆向+容斥

    http://acm.hdu.edu.cn/showproblem.php?pid=5072 求n个不同的数(<=1e5)中有多少组三元组(a, b, c)两两不互质或者两两互质. 逆向求解,把 ...

  2. MEAN 27

    添加评论主题页,在26的基础上. 新建了很多文件 Error: Cannot find module './controllers/customers_c' 解决办法:../ 接下来做function ...

  3. ASP.NET Web API 框架研究 Web Host模式下的消息处理管道

    寄宿的作用是开启一个进程为Web API提供一个运行环境以解决持续监听.请求监听和响应回复,即将接收到的请求转换成HttpRequestMessage对象传入管道,并将管道生成并经过处理后的HttpR ...

  4. 《Python黑帽子:黑客与渗透测试编程之道》 Windows系统提权

    环境准备: pywin32的安装在第八章的键盘记录中有,这里还需要安装wmi: 在本人的32位win7上本来是没有easy_install这个命令的,这需要安装setuptools-0.6c11.wi ...

  5. Java并发编程总结3——AQS、ReentrantLock、ReentrantReadWriteLock

    本文内容主要总结自<Java并发编程的艺术>第5章——Java中的锁. 一.AQS AbstractQueuedSynchronizer(简称AQS),队列同步器,是用来构建锁或者其他同步 ...

  6. vscode 学习笔记 —— 重构

    一.vscode 自带 1.提取变量 2.提取方法 上面都是通过选中文本后出现的小灯泡操作的: 3.全局替换(多个文件中的)某个变量 选中变量按 F2,输入完成后按回车 二.vscode 插件 js- ...

  7. Data - Hadoop单机配置 - 使用Hadoop2.8.0和Ubuntu16.04

    系统版本 anliven@Ubuntu1604:~$ uname -a Linux Ubuntu1604 4.8.0-36-generic #36~16.04.1-Ubuntu SMP Sun Feb ...

  8. 【bzoj3218】a+b Problem 最小割+主席树

    数据范围:$n≤5000$,$a,l,r≤10^9$,$b,w,p≤2\times 10^5$. 我们考虑一种暴力的最小割做法: 首先令$sum=\sum\limits_{i=1}^{n} b_i+w ...

  9. Docker三剑客之常用命令

    一.docker-machine 命令 说明 docker-machine create 创建一个 Docker 主机(常用-d virtualbox) docker-machine ls 查看所有的 ...

  10. android 回调函数使用简介

    //1---定义回调函数 public interface GirdMenuStateListener { void onSuccess(); void onError(); } //2---使用的地 ...