netty核心组件之EventLoopGroup和EventLoop
这节我们着重介绍netty最为核心的组件EventLoopGroup和EventLoop
EventLoopGroup:顾名思义就是EventLoop的组,下面来看它们的继承结构


在netty中我们可以把EventLoop看做一个线程,当然线程不单是jdk中的的线程,它们都从Executor一路继承过来,NioEventLoop继承SinfleThreadEventLoop,从名字可以看出它是一个单线程的EventLoop,
我们先来看NioEventLoop是如何构造的
public NioEventLoopGroup() {
this(0);
}
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);
}
~~~~~~~~~~~~~
public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory,
final RejectedExecutionHandler rejectedExecutionHandler) {
super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory, rejectedExecutionHandler);
}
NioEventLoop构造函数非常多,每个参数都可以定制,我就不全贴出来了,最后回到这个参数最全的构造函数,下面我们挨个解释每个参数的作用
- nThreads: 线程数,对应EventLoop的数量,为0时 默认数量为CPU核心数*2
- executor: 这个我们再熟悉不过,最终用来执行EventLoop的线程
- chooserFactor: 当我们提交一个任务到线程池,chooserFactor会根据策略选择一个线程来执行
- selectorProvider:用来实例化jdk中的selector,没一个EventLoop都有一个selector
- selectStrategyFactory:用来生成后续线程运行时对应的选择策略工厂
- rejectedExecutionHandler:跟jdk中线程池中的作用一样,用于处理线程池没有多余线程的情况,默认直接抛出异常
接着我们进入父类MultithreadEventLoopGroup的构造函数
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
} if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
// 创建nThreads大小的EventLoop数组
children = new EventExecutor[nThreads]; for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
// 创建具体的EventLoop,会调用子类NioEventLoopGruop中的方法
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
// 如果其中有一个创建失败,把之前创建好的都关闭掉
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
} for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
// 把刚才创建好的EventLoop提供给EventExecutorChooser,用于后续选择
chooser = chooserFactory.newChooser(children); // 添加一个EventLoop监听器,用来监听EventLoop终止状态
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
}; for (EventExecutor e: children) {
// 循环加入
e.terminationFuture().addListener(terminationListener);
}
// 将EventLoop数组转成一个只读的set
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
我们继续跟到父类NioEventLoopGroup中的newChild
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
可以看出先用来创建EventLoopGroup的参数其实都是用来创建EventLoop的,我们继续跟NioEventLoop的构造
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
if (selectorProvider == null) {
throw new NullPointerException("selectorProvider");
}
if (strategy == null) {
throw new NullPointerException("selectStrategy");
}
provider = selectorProvider;
// 创建selector,由此可见每一个EventLoop都会有一个selector
final SelectorTuple selectorTuple = openSelector();
selector = selectorTuple.selector;
unwrappedSelector = selectorTuple.unwrappedSelector;
selectStrategy = strategy;
} protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedHandler) {
super(parent);
this.addTaskWakesUp = addTaskWakesUp;
this.maxPendingTasks = Math.max(16, maxPendingTasks);
this.executor = ObjectUtil.checkNotNull(executor, "executor");
// 用来添加task的阻塞队列 链表结构
taskQueue = newTaskQueue(this.maxPendingTasks);
rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}
这里我们只是创建EventLoop,同时设置了执行的线程池、selector、taskQueue,并添加一个监听器用来监听它们的关闭状态,当所有线程都全部处于关闭状态terminationFuture会被置为true,到此还是没有实际创建可执行的thread。
后续我们在介绍channel的时候就知道EventLoop和channel如何建立关系,什么时候执行线程,我们姑且把EventLoop当做一个可执行runnable的netty线程
netty核心组件之EventLoopGroup和EventLoop的更多相关文章
- Netty 核心组件 EventLoop 源码解析
前言 在前文 Netty 启动过程源码分析 (本文超长慎读)(基于4.1.23) 中,我们分析了整个服务器端的启动过程.在那篇文章中,我们重点关注了启动过程,而在启动过程中对核心组件并没有进行详细介绍 ...
- 【Netty】Netty核心组件介绍
一.前言 前篇博文体验了Netty的第一个示例,下面接着学习Netty的组件和其设计. 二.核心组件 2.1. Channel.EventLoop和ChannelFuture Netty中的核心组件包 ...
- Netty核心组件介绍及手写简易版Tomcat
Netty是什么: 异步事件驱动框架,用于快速开发高i性能服务端和客户端 封装了JDK底层BIO和NIO模型,提供高度可用的API 自带编码解码器解决拆包粘包问题,用户只用关心业务逻辑 精心设计的Re ...
- Netty学习摘记 —— 再谈EventLoop 和线程模型
本文参考 本篇文章是对<Netty In Action>一书第七章"EventLoop和线程模型"的学习摘记,主要内容为线程模型的概述.事件循环的概念和实现.任务调度和 ...
- Netty 核心组件 Pipeline 源码分析(二)一个请求的 pipeline 之旅
目录大纲: 前言 针对 Netty 例子源码做了哪些修改? 看 pipeline 是如何将数据送到自定义 handler 的 看 pipeline 是如何将数据从自定义 handler 送出的 总结 ...
- [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现
NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...
- [编织消息框架][netty源码分析]5 eventLoop 实现类NioEventLoopGroup职责与实现
分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...
- Netty 核心组件笔记
Netty是一款高效的NIO框架和工具,基于JAVA NIO提供的API实现. 在JAVA NIO方面Selector给Reactor模式提供了基础,Netty结合Selector和Reactor模式 ...
- Netty源代码学习——EventLoopGroup原理:NioEventLoopGroup分析
类结构图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd29ya2luZ19icmFpbg==/font/5a6L5L2T/fontsize/400/f ...
随机推荐
- PHP代码审计分段讲解(3)
05 ereg正则%00截断 放上源代码 <?php $flag = "flag"; if (isset ($_GET['password'])) { if (ereg (& ...
- Acwing 405. 将他们分好队
大型补档计划 题目链接 看到分成两组,想到二分图判定 + 染色. 二分图的特点是两个有矛盾的点连一条边,考虑在这道题中,如果 \(a, b\) 中有一个人不认识对方(或者两个人互不认识),就不可能分在 ...
- 纯css 实现文本换行
业务场景:dialog中嵌套的表单,实现信息展示,由于存储路径过长并且在一行显示,导致多出的文字出现在弹出框外面了,页面极丑,所以需要将存储路径实现自动换行. 技术点:<p style=&quo ...
- 主从复制直接转换MGR_5.7验证试验
环境信息 IP port role info 192.168.188.51 4000 node1 master 192.168.188.52 4000 node2 slave1 192.168.188 ...
- Spark Connector Reader 原理与实践
本文主要讲述如何利用 Spark Connector 进行 Nebula Graph 数据的读取. Spark Connector 简介 Spark Connector 是一个 Spark 的数据连接 ...
- 多任务-python实现-进程pool(2.1.9)
@ 目录 1. 概念 2.python代码实现 1. 概念 当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动 ...
- XCTF EasyHook
无壳,使用IDA直接分析主函数 逻辑很简单,问题的关键是Hook,题目也是EasyHook, 会发现在生成文件后,文件内容是被加密后的,那就怀疑加密函数参与Hook 动态调试一步步来看,先进入4012 ...
- ceph新加存储节点
随着业务的扩展,原有的存储池不够用了,这时我们就需要给ceph添加新的存储节点,这里以新加ceph-host-05节点为例 准备工作 给所有节点hosts文件添加10.30.1.225 ceph- ...
- 走进 Python 类的内部
这篇文章和大家一起聊一聊 Python 3.8 中类和对象背后的一些概念和实现原理,主要尝试解释 Python 类和对象属性的存储,函数和方法,描述器,对象内存占用的优化支持,以及继承与属性查找等相关 ...
- C# 7-zip 压缩和解压缩
using System; using System.Collections.Generic; using System.Text; using SevenZip; using System.IO; ...