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. 7.与python交互

    与python交互 在熟练使用sql语句的基础上,开始使用python语言提供的模块与mysql进行交互 这是我们在工作中大事要做的事 先学会sql是基础,一定要熟练编写sql语句 安装引入模块 安装 ...

  2. windows 7 下elasticsearch5.0 安装head 插件

    windows 7 下elasticsearch5.0 安装head 插件 elasticsearch5.0 和2有了很大的变化,以前的很多插件都有了变化比如 bigdesk head,以下是安装he ...

  3. ASP.NET MVC 使用Unity实现Ioc

    为什么有这篇文章 最近在学ASP.NET MVC项目中使用Ioc,选用了Unity作为依赖注入的容器组件,在网上找了相关的文章简单实现了依赖注入,但想用文件配置的方式进行容器注入的注册,发现相关的文章 ...

  4. 201621123018《Java程序设计》第5周学习报告

    1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 接口.interface.implements.Comparable.Comparator. 1.2 尝试使用思维导图将这些关键 ...

  5. Android---------------ContentProvider的学习

    1.Uri  uri = Intent.getData()------------->可以获得Uri的地址 2.Cursor cursor = getContentResolver().quer ...

  6. mysql多列索引和最左前缀

    数据库的索引可以加快查询速度,原因是索引使用特定的数据结构(B-Tree)对特定的列额外组织存放,加快存储引擎(索引是存储引擎实现)查找记录的速度.索引优化是数据库优化的最重要手段. 如果查询语句使用 ...

  7. SpringCloud之Eureka集群

    前面我们介绍了SpringCloud注册中心Eureka,但是存在一个单点故障的问题,一个注册中心远远不能满足实际的生产环境,现在我们介绍一下如何搭建一个Eureka集群. 一:集群环境搭建 我们先建 ...

  8. 交换机与VLAN

    1. 交换机 1.1 定义 交换机是一种基于MAC地址识别,能完成封装转发数据帧功能的网络设备. HUB集线器是一种物理层共享设备,HUB本身不能识别MAC 地址和IP地址,当同一局域网内的A主机给B ...

  9. tomcat服务的启动与隐藏启动(win)

    一:  tomcat的启动与隐藏启动 1. 正常启动:D:\apache-tomcat-8.5.24\bin中的   startup.bat  双击启动 2. 启动tomcat服务后,window下方 ...

  10. [原创]K8飞刀20150720 新增Shellcode Loader支持多种格式

    工具: K8飞刀编译: 自己查壳组织: K8搞基大队[K8team]作者: K8拉登哥哥博客: http://qqhack8.blog.163.com发布: 2015/7/20 3:00:18 简介: ...