今天继续走读netty源码
上次走读到NioEventLoop的register方法,进入NioEventLoop类中,发现register方法并不在该类中,而是在父类SingleThreadEventLoop中,进入父类的对应方法后,发现最终调用的是unsafe的register方法
channel.unsafe().register(this, promise);
有两个参数的register方法是在AbstractChannel类中定义,继续进入AbstractChannel类中查看,发现调用的是unsafe的register方法
channel.unsafe().register(this, promise);
而unsafe的register方法定义在AbstractUnsafe内部类中,进入到AbstractUnsafe类的对应方法中就会看到如下判断
if (eventLoop.inEventLoop()) { register0(promise); } else { try { eventLoop.execute(new OneTimeTask() { @Override public void run() { register0(promise); } }); } catch (Throwable t) { } }
先看inEventLoop方法干了什么事
inEventLoop方法是定义在AbstractEventExecutor类中的,而AbstractEventExecutor类中对应的方法又调用了子类SingleThreadEventExecutor的inEventLoop方法,如下是SingleThreadEventExecutor的inEventLoop方法
public boolean inEventLoop(Thread thread) { return thread == this.thread; }
其中参数thread是代表当前线程,所以该方法其实在判断当前线程是否是SingleThreadEventExecutor类中定义的thread。由于我们现在是从main方法中进入的,当然不是了,所以inEventLoop方法返回false
程序应该进入else分支了,else分支调用的是execute方法,传入的是OneTimeTask类的实例。
从NioEventLoop方法中查找execute方法,就会发现execute方法在SingleThreadEventExecutor类中定义
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方法
private void startThread() { if (STATE_UPDATER.get(this) == ST_NOT_STARTED) { if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) { delayedTaskQueue.add(new ScheduledFutureTask<Void>( this, delayedTaskQueue, Executors.<Void>callable(new PurgeTask(), null), ScheduledFutureTask.deadlineNanos(SCHEDULE_PURGE_INTERVAL), -SCHEDULE_PURGE_INTERVAL)); thread.start(); } } }先判断线程有没有启动,如果没有启动,现将STATE_UPDATER以CAS方式设置为启动,成功后在delayedTaskQueue中增加一个任务,然后启动thread(注意,现在程序除了主线程外,增加了thread线程)
然后再看addTask方法,这个方法很简单,将传入的OneTimeTask增加到taskQueue队列中
最后看是否需要调用wakeup方法
1、看addTaskWakesUp变量是否为true,还是需要回到NioEventLoopGroup类的newChild方法中去寻找,最后发现addTaskWakesUp变量为false,
2、看wakesUpForTask方法返回是否为true,wakesUpForTask方法在SingleThreadEventExecutor中定义,但该方法是protected,所以还需要查找是否有覆盖(这个是走读代码经常会遇到的问题,eclipse中在调用的方法上直接按Ctrl+T),发现SingleThreadEventLoop中重写了该方法
protected boolean wakesUpForTask(Runnable task) { return !(task instanceof NonWakeupRunnable); }
task当然不是NonWakeupRunnable类型了,所以该方法返回true
进入wakeup方法,发现wakeup做的唯一一件事是taskQueue中增加了一个WAKEUP_TASK,而WAKEUP_TASK的run方法什么都不做。
终于register方法走读完了,这个应该算是netty中一个比较重要的方法吧
现在回到SingleThreadEventLoop的register方法,发现register方法返回的是DefaultChannelPromise的实例,而这个promise一直以参数方式传递到到AbstractUnsafe类中register0方法中,而register0方法是在thread线程中调用,所以promise是在线程中设置值的
现在回到了AbstractBootstrap类的doBind方法,查看doBind,发现返回的promise并不是register方法返回的promise,而是一个新的promise(同样是DefaultChannelPromise类的实例)
if (regFuture.isDone()) { promise = channel.newPromise(); doBind0(regFuture, channel, localAddress, promise); } else { // Registration future is almost always fulfilled already, but just in case it's not. promise = new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE); regFuture.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { doBind0(regFuture, channel, localAddress, promise); } }); }由于返回的regFuture是在单独的线程中设置值的,所以我们可以先假定isDone方法返回的是false(线程还没有设置对应的值),所以进入else分支,else分支中主要是regFuture增加了一个监听器
相关推荐
### Apache Spark源码走读之五:DStream处理的容错性分析 #### 环境搭建与背景 为了深入理解Apache Spark Streaming中DStream处理的容错机制,本文将从一个简单的Spark Streaming示例出发,逐步分析Spark如何确保...
### Apache Spark源码走读之3 -- Task运行期之函数调用关系分析 #### 概述 Apache Spark作为一款高效的大数据处理框架,在其内部有着复杂的任务调度与执行机制。本文将深入探讨Spark中Task执行期间的具体流程以及...
搭建步骤主要包括下载Spark二进制包,安装Scala、sbt和Java,并通过配置文件修改环境变量,如将$SPARK_HOME/conf目录下的spark-env.sh.template重命名为spark-env.sh,并设置相应的环境变量,以便正确启动master和...
本文档是关于Storm源码的详细走读笔记,主要分析了Storm的启动场景、Topology提交过程、worker进程中的线程使用情况、消息传递机制以及 TridentTopology的创建和ack机制等多个方面。 首先,文档提到了Storm集群中的...
### Apache Spark源码走读之四:DStream实时流数据处理 #### 一、系统概述与流数据特性 本文档探讨了Apache Spark Streaming的核心概念之一——**DStream**(Discretized Stream)及其如何实现对实时流数据的有效...
### Apache Spark 源码解析概述 #### 一、引言 ...通过对Spark源码的学习,不仅可以深入了解其内部机制,还能更好地利用其功能特性来优化大数据处理应用。希望本文能为您的学习之旅提供有价值的参考。
"二次雷达代码走读文档" 二次雷达代码走读文档是关于二次雷达系统的详细代码分析报告,涵盖了二次雷达的准备工作、程序结构、函数检查等方面的知识点。 一、准备工作 二次雷达文件位于 peripherals 目录下,包括...
《学生走读管理暂行办法》是针对在校大学生走读情况而制定的一项管理政策,旨在满足部分学生因特殊原因需要不住校的需求,同时确保学生在外的人身安全和学业不受影响。以下是该办法的主要内容和相关规定: 1. **...
### Apache Spark源码走读:如何进行代码跟读 #### 概述 本文旨在探讨如何有效地进行Apache Spark源码的阅读与理解。Apache Spark作为一款高性能的分布式计算框架,在大数据处理领域占据着重要地位。其核心由Scala...
**二、基于决策表的测试**: - 决策表测试是一种系统地构造测试用例的方法,它基于输入条件和预期输出的关系。在这个例子中,决策表包括不同的成绩范围(如90-100,80-89,70-79,60-69,0-59,以及x>100)以及对应...
文档标题和描述中并没有涉及到IT行业的具体知识点,其主要内容是一个学生的走读申请,涉及的是教育管理和个人事务管理的范畴。由于标签为空,我们无法从标签中获取额外的IT信息。因此,按照要求,我将不会生成任何与...
### nova-compute源码分析 #### 一、Nova概述及工作职责 **1.1 Nova的角色与任务** Nova是OpenStack项目中一个至关重要的组成部分,它主要负责虚拟机实例的生命周期管理,包括创建、调度、运行和销毁等功能。具体...
本篇将基于给定的“C++代码走读意见--开发注意事项”文件中的内容,详细探讨其中提及的关键知识点:内存泄漏问题及解决方案。 ##### 内存泄漏问题分析 **问题场景描述**: 在项目开发过程中,由于未妥善处理动态...
对于深度运维和二次开发者来说,理解HDFS的源码至关重要。 HDFS的设计灵感来源于Google的GFS(Google File System),它将大型文件分割成块,并将这些块分布在多台服务器上,从而实现数据的高可用性和容错性。HDFS...
### MINA源码走读与实例 #### 一、MINA概述 **MINA**(**M**ulti **I**nterface **N**etwork **A**pplication)是Apache组织下的一款开源网络通信框架,它主要针对TCP/IP、UDP/IP协议栈提供了高效的封装和扩展能力...
java8 源码 IDEA走读Java源码坏境搭建 新建一个普通java项目(如:java8-source) 创建package(tech.sqlclub.java_source)存放...到此,你可以开始尽情地撸java源码了,记住尽量要多读源码,多读源码,多学习,共勉!
- **day student**:走读生(原意为“白天的学生”,但在中文中我们通常说“走读生”来表示不在学校住宿的学生) - **in the dark**:一无所知(原意为“在黑暗中”,比喻不知道某些事情) - **cash crops**:经济...
Arraylist扩容原理走读
- 数据结构应尽可能本地化,仅通过定义良好的访问函数来访问和修改,这样可以降低出错风险,提高代码的封装性。 6. **接口设计**: - 对外部实体的接口策略需要明确定义,以保证通信的稳定性和安全性。 - 接口...