这节我们着重介绍netty最为核心的组件EventLoopGroup和EventLoop

EventLoopGroup:顾名思义就是EventLoop的组,下面来看它们的继承结构

在netty中我们可以把EventLoop看做一个线程,当然线程不单是jdk中的的线程,它们都从Executor一路继承过来,NioEventLoop继承SinfleThreadEventLoop,从名字可以看出它是一个单线程的EventLoop,

我们先来看NioEventLoop是如何构造的

  1. public NioEventLoopGroup() {
  2. this(0);
  3. }
  4. public NioEventLoopGroup(int nThreads) {
  5. this(nThreads, (Executor) null);
  6. }
  7. ~~~~~~~~~~~~~
  8. public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
  9. final SelectorProvider selectorProvider,
  10. final SelectStrategyFactory selectStrategyFactory,
  11. final RejectedExecutionHandler rejectedExecutionHandler) {
  12. super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory, rejectedExecutionHandler);
  13. }

NioEventLoop构造函数非常多,每个参数都可以定制,我就不全贴出来了,最后回到这个参数最全的构造函数,下面我们挨个解释每个参数的作用

  • nThreads: 线程数,对应EventLoop的数量,为0时 默认数量为CPU核心数*2
  • executor: 这个我们再熟悉不过,最终用来执行EventLoop的线程
  • chooserFactor: 当我们提交一个任务到线程池,chooserFactor会根据策略选择一个线程来执行
  • selectorProvider:用来实例化jdk中的selector,没一个EventLoop都有一个selector
  • selectStrategyFactory:用来生成后续线程运行时对应的选择策略工厂
  • rejectedExecutionHandler:跟jdk中线程池中的作用一样,用于处理线程池没有多余线程的情况,默认直接抛出异常

接着我们进入父类MultithreadEventLoopGroup的构造函数

  1. protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
  2. EventExecutorChooserFactory chooserFactory, Object... args) {
  3. if (nThreads <= 0) {
  4. throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
  5. }
  6.  
  7. if (executor == null) {
  8. executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
  9. }
  10. // 创建nThreads大小的EventLoop数组
  11. children = new EventExecutor[nThreads];
  12.  
  13. for (int i = 0; i < nThreads; i ++) {
  14. boolean success = false;
  15. try {
  16. // 创建具体的EventLoop,会调用子类NioEventLoopGruop中的方法
  17. children[i] = newChild(executor, args);
  18. success = true;
  19. } catch (Exception e) {
  20. // TODO: Think about if this is a good exception type
  21. throw new IllegalStateException("failed to create a child event loop", e);
  22. } finally {
  23. if (!success) {
  24. // 如果其中有一个创建失败,把之前创建好的都关闭掉
  25. for (int j = 0; j < i; j ++) {
  26. children[j].shutdownGracefully();
  27. }
  28.  
  29. for (int j = 0; j < i; j ++) {
  30. EventExecutor e = children[j];
  31. try {
  32. while (!e.isTerminated()) {
  33. e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
  34. }
  35. } catch (InterruptedException interrupted) {
  36. // Let the caller handle the interruption.
  37. Thread.currentThread().interrupt();
  38. break;
  39. }
  40. }
  41. }
  42. }
  43. }
  44. // 把刚才创建好的EventLoop提供给EventExecutorChooser,用于后续选择
  45. chooser = chooserFactory.newChooser(children);
  46.  
  47. // 添加一个EventLoop监听器,用来监听EventLoop终止状态
  48. final FutureListener<Object> terminationListener = new FutureListener<Object>() {
  49. @Override
  50. public void operationComplete(Future<Object> future) throws Exception {
  51. if (terminatedChildren.incrementAndGet() == children.length) {
  52. terminationFuture.setSuccess(null);
  53. }
  54. }
  55. };
  56.  
  57. for (EventExecutor e: children) {
  58. // 循环加入
  59. e.terminationFuture().addListener(terminationListener);
  60. }
  61. // 将EventLoop数组转成一个只读的set
  62. Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
  63. Collections.addAll(childrenSet, children);
  64. readonlyChildren = Collections.unmodifiableSet(childrenSet);
  65. }

我们继续跟到父类NioEventLoopGroup中的newChild

  1. protected EventLoop newChild(Executor executor, Object... args) throws Exception {
  2. return new NioEventLoop(this, executor, (SelectorProvider) args[0],
  3. ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
  4. }

可以看出先用来创建EventLoopGroup的参数其实都是用来创建EventLoop的,我们继续跟NioEventLoop的构造

  1. NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
  2. SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
  3. super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
  4. if (selectorProvider == null) {
  5. throw new NullPointerException("selectorProvider");
  6. }
  7. if (strategy == null) {
  8. throw new NullPointerException("selectStrategy");
  9. }
  10. provider = selectorProvider;
  11. // 创建selector,由此可见每一个EventLoop都会有一个selector
  12. final SelectorTuple selectorTuple = openSelector();
  13. selector = selectorTuple.selector;
  14. unwrappedSelector = selectorTuple.unwrappedSelector;
  15. selectStrategy = strategy;
  16. }
  17.  
  18. protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
  19. boolean addTaskWakesUp, int maxPendingTasks,
  20. RejectedExecutionHandler rejectedHandler) {
  21. super(parent);
  22. this.addTaskWakesUp = addTaskWakesUp;
  23. this.maxPendingTasks = Math.max(16, maxPendingTasks);
  24. this.executor = ObjectUtil.checkNotNull(executor, "executor");
  25. // 用来添加task的阻塞队列 链表结构
  26. taskQueue = newTaskQueue(this.maxPendingTasks);
  27. rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
  28. }

这里我们只是创建EventLoop,同时设置了执行的线程池、selector、taskQueue,并添加一个监听器用来监听它们的关闭状态,当所有线程都全部处于关闭状态terminationFuture会被置为true,到此还是没有实际创建可执行的thread。

后续我们在介绍channel的时候就知道EventLoop和channel如何建立关系,什么时候执行线程,我们姑且把EventLoop当做一个可执行runnable的netty线程

netty核心组件之EventLoopGroup和EventLoop的更多相关文章

  1. Netty 核心组件 EventLoop 源码解析

    前言 在前文 Netty 启动过程源码分析 (本文超长慎读)(基于4.1.23) 中,我们分析了整个服务器端的启动过程.在那篇文章中,我们重点关注了启动过程,而在启动过程中对核心组件并没有进行详细介绍 ...

  2. 【Netty】Netty核心组件介绍

    一.前言 前篇博文体验了Netty的第一个示例,下面接着学习Netty的组件和其设计. 二.核心组件 2.1. Channel.EventLoop和ChannelFuture Netty中的核心组件包 ...

  3. Netty核心组件介绍及手写简易版Tomcat

    Netty是什么: 异步事件驱动框架,用于快速开发高i性能服务端和客户端 封装了JDK底层BIO和NIO模型,提供高度可用的API 自带编码解码器解决拆包粘包问题,用户只用关心业务逻辑 精心设计的Re ...

  4. Netty学习摘记 —— 再谈EventLoop 和线程模型

    本文参考 本篇文章是对<Netty In Action>一书第七章"EventLoop和线程模型"的学习摘记,主要内容为线程模型的概述.事件循环的概念和实现.任务调度和 ...

  5. Netty 核心组件 Pipeline 源码分析(二)一个请求的 pipeline 之旅

    目录大纲: 前言 针对 Netty 例子源码做了哪些修改? 看 pipeline 是如何将数据送到自定义 handler 的 看 pipeline 是如何将数据从自定义 handler 送出的 总结 ...

  6. [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现

    NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...

  7. [编织消息框架][netty源码分析]5 eventLoop 实现类NioEventLoopGroup职责与实现

    分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...

  8. Netty 核心组件笔记

    Netty是一款高效的NIO框架和工具,基于JAVA NIO提供的API实现. 在JAVA NIO方面Selector给Reactor模式提供了基础,Netty结合Selector和Reactor模式 ...

  9. Netty源代码学习——EventLoopGroup原理:NioEventLoopGroup分析

    类结构图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd29ya2luZ19icmFpbg==/font/5a6L5L2T/fontsize/400/f ...

随机推荐

  1. Raft概述

    Raft 1. 概述 Raft是一种一致性(共识)算法,相比Paxos,Raft更容易理解和实现,它将分布式一致性问题分解成多个子问题,Leader选举(Leader election).日志复制(L ...

  2. 【题解】折纸 origami [SCOI2007] [P4468] [Bzoj1074]

    [题解]折纸 origami [SCOI2007] [P4468] [Bzoj1074] 传送门:折纸 \(\text{origami [SCOI2007] [P4468]}\) \(\text{[B ...

  3. 《深入理解计算机系统》实验三 —— Buf Lab

    这是CSAPP的第三个实验,主要让我们熟悉GDB的使用,理解程序栈帧的结构和缓冲区溢出的原理. 实验目的   本实验的目的在于加深对IA-32函数调用规则和栈结构的具体理解.实验的主要内容是对一个可执 ...

  4. STL——容器(Set & multiset)的删除 erase

    set.clear();             //清除所有元素 set.erase(pos);     //删除pos迭代器所指的元素,返回下一个元素的迭代器. set.erase(beg,end ...

  5. 安卓实用工具箱v4.3几百种小功能

    款多功能实用工具箱.提供了从日常.图片.查询.设备.辅助.提取.优惠券.趣味游戏等多方面的功能,操作简单,即点即用,避免您下载超多应用的难题,且应用体积轻巧,界面简洁.已去除广告! 下载地址:http ...

  6. Java中四舍五入

    1.Math中四舍五入的方法 Math.ceil(double a)向上舍入,将数值向上舍入为最为接近的整数,返回值是double类型 Math.floor(double a)向下舍入,将数值向下舍入 ...

  7. oracle 11g修改归档日志目录及大小

    1.查看当前归档日志目录 SQL> show parameter recovery NAME TYPE VALUE ------------------------------------ -- ...

  8. 解决因缺少驱动程序,导致“未在本地计算机上注册microsoft.ace.12.0”异常

    写了一个winform程序,功能是选择一个excel表格,把里面的内容写进sqlite数据库中,在本地测试没问题,但是在其他电脑上就会报错"未在本地计算机上注册microsoft.ace.1 ...

  9. 02-flask-路由基础

    代码 from flask import Flask # 创建Flask对象 app = Flask(__name__) # 定义路由 @app.route('/') def index(): # 函 ...

  10. 仵航说 Vue用replace修改数组中对象的键值或者字段名 仵老大

    仵航说 Vue用replace修改数组中对象的键值或者字段名 仵老大 1.介绍 先看图 ​ 今天在项目中遇到了一个问题,例如我现在需要传一些数据到后端,数组例如是 let arr = [ {" ...