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职责与实现的更多相关文章

  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源码分析]6 ChannelPipeline 实现类DefaultChannelPipeline职责与实现

    ChannelPipeline 负责channel数据进出处理,如数据编解码等.采用拦截思想设计,经过A handler处理后接着交给next handler ChannelPipeline 并不是直 ...

  4. [编织消息框架][netty源码分析]11 ByteBuf 实现类UnpooledHeapByteBuf职责与实现

    每种ByteBuf都有相应的分配器ByteBufAllocator,类似工厂模式.我们先学习UnpooledHeapByteBuf与其对应的分配器UnpooledByteBufAllocator 如何 ...

  5. [编织消息框架][netty源码分析]8 Channel 实现类NioSocketChannel职责与实现

    Unsafe是托委访问socket,那么Channel是直接提供给开发者使用的 Channel 主要有两个实现 NioServerSocketChannel同NioSocketChannel 致于其它 ...

  6. [编织消息框架][netty源码分析]9 Promise 实现类DefaultPromise职责与实现

    netty Future是基于jdk Future扩展,以监听完成任务触发执行Promise是对Future修改任务数据DefaultPromise是重要的模板类,其它不同类型实现基本是一层简单的包装 ...

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

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

  8. [编织消息框架][netty源码分析]7 Unsafe 实现类NioSocketChannelUnsafe职责与实现

    Unsafe 是channel的内部接口,从书写跟命名上看是不公开给开发者使用的,直到最后实现NioSocketChannelUnsafe也没有公开出去 public interface Channe ...

  9. [编织消息框架][netty源码分析]13 ByteBuf 实现类CompositeByteBuf职责与实现

    public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf ...

随机推荐

  1. response.text与content的区别

    在某些情况下来说,response.text 与 response.content 都是来获取response中的数据信息,效果看起来差不多.那么response.text 和 response.co ...

  2. STM32硬件错误HardFault_Handler的处理方法

    https://blog.csdn.net/electrocrazy/article/details/78173558

  3. LUOGU P1402 酒店之王 (网络流)

    解题思路 应该比较显然得能看出这是个网络流,将$S$与房间连边,房间与人连边,人与菜连边,菜与汇点连边,边的流量均为1.但这样是错误的,因为有可能一个人跑过去2的流量,所以要将人拆点限流. #incl ...

  4. Installer - Eclipse配置Data Source Explorer

    一.配置Oracle数据库连接 1.打开配置窗口 在[window]菜单中的[show windows]选择[other],在弹出的窗口中选择[Data Source Explorer]进行数据数据库 ...

  5. 14. TIM of STM32F103ZE

    block diagram 14.3.1 Time-base unit 有三个基础的寄存器: 计数寄存器(TIMx_CNT) 预分配寄存器(TIMx_PSC), 自动重载寄存器(TIMx_ARR) 重 ...

  6. “瑞士军刀”Netcat使用方法总结

    前言 最近在做渗透测试的时候遇到了端口监听和shell的反弹问题,在这个过程中自己对Netcat这一款神器有了新的认识,现将一些Netcat的用法做一个小总结,希望对各位有帮助! Netcat简介 N ...

  7. UASCO Cow Pedigrees /// oj10140

    题目大意: 输入n,m :二叉树 输出 n个点分为m层 的方案数: 每个点的分支要么是0要么是2 Sample Input 5 3 Sample Output 2 即 两个方案为          O ...

  8. Resource Archiver HDU - 3247 AC自动机+BFS+状压

    题意: 给出n个资源串,m个病毒串,现在要如何连接资源串使得不含病毒串(可以重叠,样例就是重叠的). 题解: 这题的套路和之前的很不同了,之前的AC自动机+DP的题目一般都是通过teir图去转移, 这 ...

  9. Activiti流程图查看

    1.测试用例查看图片 public void viewImage() throws Exception { // 创建仓库服务对对象 RepositoryService repositoryServi ...

  10. C++ 系列:extern

    extern 作用1:声明外部变量现代编译器一般采用按文件编译的方式,因此在编译时,各个文件中定义的全局变量是互相透明的,也就是说,在编译时,全局变量的可见域限制在文件内部. 例1:创建一个工程,里面 ...