[netty源码分析]3 eventLoop 实现类SingleThreadEventLoop职责与实现
eventLoop是基于事件系统机制,主要技术由线程池同队列组成,是由生产/消费者模型设计,那么先搞清楚谁是生产者,消费者内容
SingleThreadEventLoop 实现
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
private final Queue<Runnable> tailTasks;
@Override
protected void afterRunningAllTasks() {
runAllTasksFrom(tailTasks);
}
}
SingleThreadEventLoop是个抽象类,从实现代码上看出很简单的逻辑边界判断
SingleThreadEventExecutor也是个抽象类,代码量比较大,我们先看重要的成员属性
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
//事件队列
private final Queue<Runnable> taskQueue;
//执行事件线程,可以看出只有一个线程只要用来记录executor的当前线程
private volatile Thread thread;
//主要负责监控该线程的生命周期,提取出当前线程然后用thread记录
private final Executor executor;
//用Atomic*技术记录当前线程状态
private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "state");
}
//启动线程做了比较判断
private void startThread() {
if (STATE_UPDATER.get(this) == ST_NOT_STARTED) {
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
doStartThread();
}
}
}
private void doStartThread() {
executor.execute(new Runnable() {
@Override
public void run() {
//记录当前执行线程
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
//这里调用的是子类,注意子类是死循环不停的执行任务
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
//更改线程结束状态 省略部分代码
for (;;) {
int oldState = STATE_UPDATER.get(SingleThreadEventExecutor.this);
if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
break;
}
}
try {
// 执行未完成任务同 shutdown hooks.
for (;;) {
if (confirmShutdown()) {
break;
}
}
} finally {
try {
//最后清理操作,如 NioEventLoop实现 selector.close();
cleanup();
} finally {
//省略部分代码
}
}
}
}
});
}
protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
Runnable task = pollTaskFrom(taskQueue);
if (task == null) {
return false;
}
for (;;) {
//安全执行任务
safeExecute(task);
//继续执行剩余任务
task = pollTaskFrom(taskQueue);
if (task == null) {
return true;
}
}
}
protected final Runnable pollTaskFrom(Queue<Runnable> taskQueue) {
for (;;) {
Runnable task = taskQueue.poll();
//忽略WAKEUP_TASK类型任务
if (task == WAKEUP_TASK) {
continue;
}
return task;
}
}
protected boolean runAllTasks(long timeoutNanos) {
//先执行周期任务
fetchFromScheduledTaskQueue();
//从taskQueue提一个任务,如果为空执行所有tailTasks
Runnable task = pollTask();
//如果taskQueue没有任务,立即执行子类的tailTasks
if (task == null) {
afterRunningAllTasks();
return false;
}
//计算出超时时间 = 当前 nanoTime + timeoutNanos
final long deadline = ScheduledFutureTask.nanoTime() + timeoutNanos;
long runTasks = 0;
long lastExecutionTime;
for (;;) {
safeExecute(task);
runTasks ++;
//当执行任务次数大于64判断是否超时,防止长时间独占CPU
if ((runTasks & 0x3F) == 0) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
if (lastExecutionTime >= deadline) {
break;
}
}
task = pollTask();
if (task == null) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
break;
}
}
afterRunningAllTasks();
this.lastExecutionTime = lastExecutionTime;
return true;
}
//SingleThreadEventLoop run 实现
public class DefaultEventLoop extends SingleThreadEventLoop { @Override
protected void run() {
for (;;) {
Runnable task = takeTask();
if (task != null) {
task.run();
updateLastExecutionTime();
} if (confirmShutdown()) {
break;
}
}
}
}
我们可以在SingleThreadEventExecutor 两个runAllTasks 方法打上断点,看执行任务时调用逻辑

本人为了搞清楚 taskQueue 同tailTasks 类型任务,在任务入队时打断点,分别为 SingleThreadEventLoop executeAfterEventLoopIteration方法同 SingleThreadEventExecutor offerTask方法

ServerBootstrap[bind address] ->
NioEventLoopGroup [register Channel] -> [ChannelPromise] ->
NioEventLoop [build and push register task]
从调用链可以清晰看出,启动 netty server 绑定生成抽象 Channel 然后l转换成ChannelPromise,再调用注册实现register0
这里用了判断是否为当前线程,如果是不用加入队列马上执行,目前减少上下文切换开削
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
}
总结:
1.SingleThreadEventLoop 任务执行加了超时限制,目的防止当前线程长时间执行任务独占cpu
2.提交任务时做了减少上下文开削优化
3.执行任务优先级 1.周期任务 2.taskQueue 3.tailTasks
目前没有看到任何调用 SingleThreadEventLoop executeAfterEventLoopIteration 方法,估计是扩展处理。
4.用到Atomic*技术解决并发问题,从Executor提取当前线程,把单一线程维护交给Executor
[netty源码分析]3 eventLoop 实现类SingleThreadEventLoop职责与实现的更多相关文章
- [编织消息框架][netty源码分析]3 EventLoop 实现类SingleThreadEventLoop职责与实现
eventLoop是基于事件系统机制,主要技术由线程池同队列组成,是由生产/消费者模型设计,那么先搞清楚谁是生产者,消费者内容 SingleThreadEventLoop 实现 public abst ...
- [编织消息框架][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源码分析]6 ChannelPipeline 实现类DefaultChannelPipeline职责与实现
ChannelPipeline 负责channel数据进出处理,如数据编解码等.采用拦截思想设计,经过A handler处理后接着交给next handler ChannelPipeline 并不是直 ...
- [编织消息框架][netty源码分析]8 Channel 实现类NioSocketChannel职责与实现
Unsafe是托委访问socket,那么Channel是直接提供给开发者使用的 Channel 主要有两个实现 NioServerSocketChannel同NioSocketChannel 致于其它 ...
- [编织消息框架][netty源码分析]9 Promise 实现类DefaultPromise职责与实现
netty Future是基于jdk Future扩展,以监听完成任务触发执行Promise是对Future修改任务数据DefaultPromise是重要的模板类,其它不同类型实现基本是一层简单的包装 ...
- [编织消息框架][netty源码分析]5 EventLoopGroup 实现类NioEventLoopGroup职责与实现
分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...
- [编织消息框架][netty源码分析]11 ByteBuf 实现类UnpooledHeapByteBuf职责与实现
每种ByteBuf都有相应的分配器ByteBufAllocator,类似工厂模式.我们先学习UnpooledHeapByteBuf与其对应的分配器UnpooledByteBufAllocator 如何 ...
- [编织消息框架][netty源码分析]7 Unsafe 实现类NioSocketChannelUnsafe职责与实现
Unsafe 是channel的内部接口,从书写跟命名上看是不公开给开发者使用的,直到最后实现NioSocketChannelUnsafe也没有公开出去 public interface Channe ...
随机推荐
- PixiJS - 基于 WebGL 的超快 HTML5 2D 渲染引擎
Pixi.js 是一个开源的HTML5 2D 渲染引擎,使用 WebGL 实现,不支持的浏览器会自动降低到 Canvas 实现.PixiJS 的目标是提供一个快速且轻量级的2D库,并能兼容所有设备.此 ...
- 如何在Windows系统下安装Linux虚拟机
先安装虚拟机这个软件,然后在虚拟机里装linux. 1,准备,下载VM虚拟机,链接: http://pan.baidu.com/s/1z79oU 密码: vbap.和linux镜像文件,可以下载ubu ...
- Intellij IDEA 没办法创建java文件
然后就是具体的解释和解决方案. 如上图红圈所示,我们可以根据对项目的任意目录进行这五种目录类型标注,这个知识点非常非常重要,必须会. Sources 一般用于标注类似 src 这种可编译目录.有时候我 ...
- git-ftp 用git管理ftp空间
ftp管理不能实现版本控制,而且多电脑工作时,同步很成问题. git-ftp可以完美的解决问题 下面是我的趟坑之路,本机的环境是win10,首先你的机器得装有git. git-ftp的地址https: ...
- 【小瑕疵】表单中的button会自动提交?
在表单中使用button标签的时候会发现,即使什么类型都没有设置,但是在点击的时候会发现,表单会自动提交 比如: 我在一个表单的button中添加一个函数,当点击这个按钮时会增加一行内容: 但是当我实 ...
- 【Java SE】如何用Java实现冒泡排序
摘要: 作为一名Java开发工程师,手头如果不会几个常见的排序算法,怎么可能经过笔试题这一关呢.据我所知,许多大型的公司的笔试题都有排序题,那我们先从最简单的排序:冒泡排序开始,以后几篇博客将继续更新 ...
- 【知识学习】如何寻找真实IP
1.多地点ping查询IP,如果都一样可能没有使用cdn,如果有cdn,尝试海外地点ping查询IP 2.ping一下没有WWW的域名,可能存在真实IP.比如www.baidu.com设置了cdn,那 ...
- bzoj4031 [HEOI2015]小Z的房间
Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子.在一开始的时候,相邻的格子之间都有墙隔着. ...
- 蓝桥杯-括号问题-java
/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...
- [周译见] C# 7 中的模范和实践
原文地址:https://www.infoq.com/articles/Patterns-Practices-CSharp-7 关键点 遵循 .NET Framework 设计指南,时至今日,仍像十年 ...