EventLoop 的启动
在前面我们已经知道了,NioEventLoop 本身就是一个SingleThreadEventExecutor,因此NioEventLoop 的启动,其实就是NioEventLoop 所绑定的本地Java 线程的启动。
按照这个思路,我们只需要找到在哪里调用了SingleThreadEventExecutor 中thread 字段的start()方法就可以知道是在哪里启动的这个线程了。从前面章节的分析中, 其实我们已经清楚: thread.start() 被封装到了SingleThreadEventExecutor.startThread()方法中,来看代码:
private void startThread() {if (STATE_UPDATER.get(this) == ST_NOT_STARTED) {if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {doStartThread();}}
}
STATE_UPDATER 是SingleThreadEventExecutor 内部维护的一个属性,它的作用是标识当前的thread 的状态。在初始的时候,STATE_UPDATER == ST_NOT_STARTED,因此第一次调用startThread()方法时,就会进入到if 语句内,进而调用到thread.start()方法。而这个关键的startThread()方法又是在哪里调用的呢?用方法调用关系反向查找功能,我们发现,startThread 是在SingleThreadEventExecutor 的execute()方法中调用的:
public void execute(Runnable task) {if (task == null) {throw new NullPointerException("task");}boolean inEventLoop = inEventLoop();if (inEventLoop) {addTask(task);} else {startThread(); // 调用startThread 方法、启动EventLoop 线程addTask(task);if (isShutdown() && removeTask(task)) {reject();}}if (!addTaskWakesUp && wakesUpForTask(task)) {wakeup(inEventLoop);}
}
既然如此,那现在我们的工作就变为了寻找在哪里第一次调用了SingleThreadEventExecutor 的execute()方法。
如果细心的小伙伴可能已想到了, 我们在前面章节中, 我们有提到到在注册channel 的过程中, 会在AbstractChannel$AbstractUnsafe 的register()中调用eventLoop.execute()方法,在EventLoop 中进行Channel 注册代码的执行,AbstractChannel$AbstractUnsafe 的register()部分代码如下:
public final void register(EventLoop eventLoop, final ChannelPromise promise) {// 删除判断AbstractChannel.this.eventLoop = eventLoop;if (eventLoop.inEventLoop()) {register0(promise);} else {try {eventLoop.execute(new Runnable() {@Overridepublic void run() {register0(promise);}});} catch (Throwable t) {// 删除异常处理代码}}
}
很显然,一路从Bootstrap 的bind()方法跟踪到AbstractChannel$AbstractUnsafe 的register()方法,整个代码都是在主线程中运行的,因此上面的eventLoop.inEventLoop()返回为false,于是进入到else 分支,在这个分支中调用了eventLoop.execute()方法,而NioEventLoop 没有实现execute()方法,因此调用的是SingleThreadEventExecutor 的execute()方法:
public void execute(Runnable task) {// 条件判断boolean inEventLoop = inEventLoop();if (inEventLoop) {addTask(task);} else {startThread();addTask(task);if (isShutdown() && removeTask(task)) {reject();}}if (!addTaskWakesUp && wakesUpForTask(task)) {wakeup(inEventLoop);}
}
我们已经分析过了, inEventLoop == false , 因此执行到else 分支, 在这里就调用startThread() 方法来启动SingleThreadEventExecutor 内部关联的Java 本地线程了。
总结一句话:当EventLoop 的execute()第一次被调用时,就会触发startThread()方法的调用,进而导致EventLoop所对应的Java 本地线程启动。
EventLoop 的启动相关推荐
- NioEventLoop启动流程源码解析
NioEventLoop的启动时机是在服务端的NioServerSocketChannel中的ServerSocketChannel初始化完成,且注册在NioEventLoop后执行的, 下一步就是去 ...
- Android之rild进程启动源码分析
Android 电话系统框架介绍 在android系统中rild运行在AP上,AP上的应用通过rild发送AT指令给BP,BP接收到信息后又通过rild传送给AP.AP与BP之间有两种通信方式: 1. ...
- Netty服务器启动源码剖析
Netty服务器启动源码剖析 文章目录 Netty服务器启动源码剖析 1.Netty服务器启动源码剖析 1.1.执行new NioEventLoopGroup()时发生了什么 1.1.1.NioEve ...
- muduo之EventLoopThread
muduo用EventLoopThread提供了对应eventloop和thread的封装,意为I/O线程类,EventLoopThread可以创建一个IO线程,通过startLoop返回一个IO线程 ...
- Netty新连接接入与NioSocketChannel分析
原文链接:https://wangwei.one/posts/net... 前面的一些章节,我们分析了Netty的三大组件 -- Channel .EventLoop.Pipeline ,对Netty ...
- netty源码分析系列——Channel
2019独角兽企业重金招聘Python工程师标准>>> 前言 Channel是netty中作为核心的一个概念,我们从启动器(Bootstrap)中了解到最终启动器的两个关键操作con ...
- Spark源码分析之DAGScheduler以及stage的划分
一 核心属性 TaskScheduler taskScheduler: task调度器 AtomicInteger nextJobId: 获取下一个jobId Int numTotalJobs:job ...
- 30muduo_net库源码分析(六)
1.EventThread (1)任何一个线程,只要创建并运行了EventLoop,都称之为IO线程 (2)IO线程不一定是主线程 (3)muduo并发模型one loop per thread + ...
- SparkSteaming运行流程分析以及CheckPoint操作
本文主要通过源码来了解SparkStreaming程序从任务生成到任务完成整个执行流程以及中间伴随的checkpoint操作 注:下面源码只贴出跟分析内容有关的代码,其他省略 1 分析流程 应用程序入 ...
最新文章
- Kubernetes 1.8.4 手动安装教程-安装Dashboard(七)
- HDU2121(最小树形图的模版算法题)
- BadTunnel:跨网段劫持广播协议
- Sierpinski镂垫
- 牛客网_PAT乙级_1010月饼 (25)
- xunsearch安装使用
- 一个java文件中可包含多个main方法
- 云漫圈 | 什么是微服务?
- 主成分分析PCA案例及原理
- 架构设计(6)---Web架构师究竟都要学些什么?
- 2018腾讯内部转岗面试题2——打印A-Z 26个字母的所有子集
- For ourselves
- dell服务器错误代码
- 古希腊神话,古罗马神话和北欧神话
- 华硕电脑(博主电脑型号为天选FA506IH)Fn组合键屏幕不显示对应操作的解决办法!!
- 大数据之路,阿里巴巴大数据实践
- 电视制式 NTSC PAL SECAM
- 树莓派打造智能语音控制系统
- 烟花绽放c语言程序设计摘要,描写烟花绽放的优美句子
- CQHTTP 以HTTP形式制作你的QQ机器人