上一篇主要介绍了一下EventLoopGroup,本篇详细看下它的成员EventLoop

类结构



NioEventLoop继承自SingleThreadEventLoop,而SingleThreadEventLoop又继承自SingleThreadEventExecutor

SingleThreadEventExecutor内部持有一个Thread对象,是Netty多线程的基础。

可以认为, 一个NioEventLoop与一个特定的线程进行了绑定,并且在其生命周期内,绑定的线程都不会再改变。

SingleThreadEventExecutor

从名字就可以看出来,SingleThreadEventExecutor是一个单线程事件执行器。主要做的事情就是线程的管理和事件的执行。

线程管理

SingleThreadEventExecutor中定义了五种线程状态:

    /**
* 未开始
*/
private static final int ST_NOT_STARTED = 1;
/**
* 已开始
*/
private static final int ST_STARTED = 2;
/**
* 关闭中
*/
private static final int ST_SHUTTING_DOWN = 3;
/**
* 已关闭
*/
private static final int ST_SHUTDOWN = 4;
/**
* 已终止
*/
private static final int ST_TERMINATED = 5;

这几种状态对应的方法有startThreadshutdownGracefullyshutdown

startThread

    private void startThread() {
if (state == ST_NOT_STARTED) {
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
try {
doStartThread();
} catch (Throwable cause) {
STATE_UPDATER.set(this, ST_NOT_STARTED);
PlatformDependent.throwException(cause);
}
}
}
}

startThread线程未开始时,尝试更新线程状态为一开始,更新成功,则调用doStartThread方法启动线程,子类的run方法就是在这里调用的,比如说接下来的NioEventLoop

shutdownGracefully

    public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
// 静待时间需要>=0
if (quietPeriod < 0) {
throw new IllegalArgumentException("quietPeriod: " + quietPeriod + " (expected >= 0)");
}
// 超时时间不能小于静待时间
if (timeout < quietPeriod) {
throw new IllegalArgumentException(
"timeout: " + timeout + " (expected >= quietPeriod (" + quietPeriod + "))");
}
// 必须设置时间单位
if (unit == null) {
throw new NullPointerException("unit");
}
// 关闭中直接返回终止Future
if (isShuttingDown()) {
return terminationFuture();
}
boolean inEventLoop = inEventLoop();
boolean wakeup;
int oldState;
for (; ; ) {
// 关闭中直接返回终止Future
if (isShuttingDown()) {
return terminationFuture();
}
int newState;
wakeup = true;
oldState = state;
if (inEventLoop) {
newState = ST_SHUTTING_DOWN;
} else {
switch (oldState) {
case ST_NOT_STARTED:
case ST_STARTED:
newState = ST_SHUTTING_DOWN;
break;
default:
newState = oldState;
wakeup = false;
}
}
if (STATE_UPDATER.compareAndSet(this, oldState, newState)) {
break;
}
}
gracefulShutdownQuietPeriod = unit.toNanos(quietPeriod);
gracefulShutdownTimeout = unit.toNanos(timeout);
if (oldState == ST_NOT_STARTED) {
try {
doStartThread();
} catch (Throwable cause) {
STATE_UPDATER.set(this, ST_TERMINATED);
terminationFuture.tryFailure(cause); if (!(cause instanceof Exception)) {
PlatformDependent.throwException(cause);
}
return terminationFuture;
}
}
if (wakeup) {
wakeup(inEventLoop);
} return terminationFuture();
}

shutdownGracefully目的是让正在执行的任务再执行一会儿,同时拒绝新任务。quietPeriodtimeout这两个时间会在confirmShutdown方法中用到,当然单位已经转为纳秒了。

事件的执行

   public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
boolean inEventLoop = inEventLoop();
if (inEventLoop) {
addTask(task);
} else {
startThread();
addTask(task);
if (isShutdown() && removeTask(task)) {
reject();
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}

NioEventLoop

NioEventLoop的核心操作都在它的run方法里面:

    protected void run() {
for (; ; ) {
try {
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.SELECT:
// 重置wakenUp为false并选择任务
select(wakenUp.getAndSet(false));
if (wakenUp.get()) {
selector.wakeup();
}
default:
}
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
// 当处理io用时占比为100%时
if (ioRatio == 100) {
try {
processSelectedKeys();
} finally {
runAllTasks();
}
} else {
final long ioStartTime = System.nanoTime();
try {
processSelectedKeys();
} finally {
final long ioTime = System.nanoTime() - ioStartTime;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
}
} catch (Throwable t) {
// 处理Loop异常
handleLoopException(t);
}
try {
// 处于关闭状态
if (isShuttingDown()) {
// 关闭所有
closeAll();
if (confirmShutdown()) {
return;
}
}
} catch (Throwable t) {
// 处理Loop异常
handleLoopException(t);
}
}
}

该方法主要是处理流程的控制,包括选择、处理和关闭这几种。

文中帖的代码注释全在:KAMIJYOUDOUMA, 有兴趣的童鞋可以关注一下。


本篇到此结束,如果读完觉得有收获的话,欢迎点赞、关注、加公众号【贰级天災】,查阅更多精彩历史!!!

Netty源码分析(五):EventLoop的更多相关文章

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

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

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

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

  3. [编织消息框架][netty源码分析]2 eventLoop

    eventLoop从命名上看是专门处理事件 事件系统主要由线程池同队列技术组成,有以下几个优点 1.任务出队有序执行,不会出现错乱,当然前提执行线程池只有一个 2.解偶系统复杂度,这是个经典的生产者/ ...

  4. [netty源码分析]3 eventLoop 实现类SingleThreadEventLoop职责与实现

    eventLoop是基于事件系统机制,主要技术由线程池同队列组成,是由生产/消费者模型设计,那么先搞清楚谁是生产者,消费者内容 SingleThreadEventLoop 实现 public abst ...

  5. [编织消息框架][netty源码分析]3 EventLoop 实现类SingleThreadEventLoop职责与实现

    eventLoop是基于事件系统机制,主要技术由线程池同队列组成,是由生产/消费者模型设计,那么先搞清楚谁是生产者,消费者内容 SingleThreadEventLoop 实现 public abst ...

  6. Netty源码分析第1章(Netty启动流程)---->第5节: 绑定端口

    Netty源码分析第一章:Netty启动步骤 第五节:绑定端口 上一小节我们学习了channel注册在selector的步骤, 仅仅做了注册但并没有监听事件, 事件是如何监听的呢? 我们继续跟第一小节 ...

  7. Netty源码分析第3章(客户端接入流程)---->第5节: 监听读事件

    Netty源码分析第三章: 客户端接入流程 第五节: 监听读事件 我们回到AbstractUnsafe的register0()方法: private void register0(ChannelPro ...

  8. Netty源码分析第4章(pipeline)---->第5节: 传播outbound事件

    Netty源码分析第五章: pipeline 第五节: 传播outBound事件 了解了inbound事件的传播过程, 对于学习outbound事件传输的流程, 也不会太困难 在我们业务代码中, 有可 ...

  9. Netty源码分析第7章(编码器和写数据)---->第5节: Future和Promies

    Netty源码分析第七章: 编码器和写数据 第五节: Future和Promise Netty中的Future, 其实类似于jdk的Future, 用于异步获取执行结果 Promise则相当于一个被观 ...

  10. 【Netty源码分析】客户端connect服务端过程

    上一篇博客[Netty源码分析]Netty服务端bind端口过程 我们介绍了服务端绑定端口的过程,这一篇博客我们介绍一下客户端连接服务端的过程. ChannelFuture future = boos ...

随机推荐

  1. 高速上手C++11 14 笔记1

    1 constexpr constexpr关键字可以让已经具备常量返回的函数运用于常量的位置. c++14起可以在函数内部使用局部变量.循环和分支等简单语句. 2 委托构造&继承构造 委托构造 ...

  2. JupyterLab绘制:柱状图,饼状图,直方图,散点图,折线图

    JupyterLab绘图 喜欢python的同学,可以到 https://v3u.cn/(刘悦的技术博客) 里面去看看,爬虫,数据库,flask,Django,机器学习,前端知识点,JavaScrip ...

  3. spring boot + vue + element-ui全栈开发入门

    今天想弄弄element-ui  然后就在网上找了个例子 感觉还是可以用的  第一步是完成了  果断 拿过来  放到我这里这  下面直接是连接  点进去 就可以用啊 本想着不用vue   直接导入连接 ...

  4. Codeforces Round #536 (Div. 2) F 矩阵快速幂 + bsgs(新坑) + exgcd(新坑) + 欧拉降幂

    https://codeforces.com/contest/1106/problem/F 题意 数列公式为\(f_i=(f^{b_1}_{i-1}*f^{b_2}_{i-2}*...*f^{b_k} ...

  5. tg代理

    安装 wget -N --no-check-certificate https://raw.githubusercontent.com/FunctionClub/MTProxy-Bash/master ...

  6. Unicode vs. UTF-8 etc.

    目测是个老问题了.随便一搜,网上各种总结过.这里不辞啰嗦,尽量简洁的备忘一下. 几个链接,有道云笔记链接,都是知乎上几个问题的摘录:阮一峰的日志,1-5 还是值得参考,但是之后的部分则混淆了 Wind ...

  7. CentOS MariaDB 安装和配置

    sudo vi /etc/yum.repos.d/mariadb.repo # MariaDB 10.1 CentOS repository list - created 2017-03-23 13: ...

  8. Missing initializer in const declaration

    这是一个 JS 的报错. 如果你要声明一个常量,必须要赋初值.否则就会报错. 比如这样就可以触发这个报错: const foo; 或者 const bar = xxx; 等号右侧由于拼写失误导致的js ...

  9. ionic3 百度地图插件定位 问题

    每次用 cordova-pluin-baidumaploaction    每调用一次  他只会执行一次 我想循环  但是每次都会初始化   把插件的java代码98行注释就好了

  10. msfconlose基本命令

    命令 简介 back 从当前上下文 banner 显示显示一个令人敬畏的metasploit横幅 cd 更改当前工作目录 color 切换颜色 connect 与主机通信 edit 使用$ VISUA ...