系列文章目录和关于我

零丶引入

在《Netty源码学习1——NioEventLoopGroup的初始化》中,我们学习了NioEventLoopGroup和NioEventLoop的初始化,在下面netty服务端启动的demo中

会在ServerBootStrap中指定Channel为Nio类型的Channel,然后启动的时候绑定端口,之前我们解释道NioEventLoop是事件循环,这里的事件是指客户端连接,数据准备就绪等IO事件,循环是指会有一个线程不断的处理任务。so 这篇我们一起看下NioEventLoop是如何产生IO事件并执行各种任务的。

一丶NioEventLoop的初始化

这部分在《Netty源码学习1——NioEventLoopGroup的初始化)》中进行了说明,其中比较有趣的是Netty对JDK原生Selector的优化,将原本基于HashSet的SelectionKey集合,修改为基于数组的SelectionKey集合,优化了迭代和修改的效率,再次就不在过多赘述了。

二丶NioEventLoop的启动

NioEventLoop中存在一个run方法,该方法是一个死循环,这便是事件循环中的循环,它由一个线程专门去执行,我们先分析下NioEventLoop#run方法是什么时候开始执行的。

如上分别是客户端和服务端启动部分的源码,在bind 和 connect中都会触发——Channel的初始化+Channel的注册。

  1. Channel的初始化:由对应的Factory进行创建(默认使用反射)

  2. Channel的注册:这里的注册将调用NioEventLoopGroup#register方法,

    这里自然是通过EventExecutorChooser#next方法选择一个NioEventLoop进行注册

    在excute方法中会将EventLoop#run方法包装成一个Runnable提交到线程池中,这里的线程池是被包装后的ThreadPerTaskExecutor,每一个任务的提交都会新建一个线程去执行

    因此可以任务NioEventLoop#run方法由一个线程单独去执行

三丶NioEventLoop#run

1.SelectStrategy控制循环

和Tomcat的Poller类似,NioEventLoop需要使用Selector去进行IO多路复用,Netty抽象出SelectStrategy使用其calculateStrategy来控制循环

其中selectNow即使用JDK Selector#selectNow方法进行非阻塞select

DefaultSelectStrategy#calculateStrategy的逻辑是,如果当前EventLoop中存在任务那么直接返回就绪的就绪SelectionKey数目,如果不存哎任务,那么返回常量SELECT(-1),根据返回的数字会进入不同的分支。

2.执行阻塞select

NioEventLoop支持调度任务,因此内部使用了优先队列保存调度任务,并且调度任务具备一个deadlineNanos属性

3.执行任务

NioEventLoop支持ioRatio指定IO事件的处理事件,和其他任务执行时间的比例

其中处理IO时间的部分涉及到Netty的ChannelPipeline的执行,这部分在后续的博客中进行讲解

3.1 runAllTasks

无参的runAllTask会在IO事件处理结束后执行,首先会将scheduledTaskQueue中的任务(未到执行时间的任务,or deadlineNanos早于当前时间的任务 不会转移到taskQueue)转移到taskQueue,然后执行taskQueue中的任务,执行完taskQueue的任务后,执行tailTasks中的任务

3.2 runAllTasks(超时时间)

大流程和上面runAllTasks类似,依旧是将调度任务从scheduledTaskQueue转移到taskQueue,然后执行taskQueue任务,然后执行tailTasks中的任务

感觉比较有趣的是,对调度任务的处理,移动到taskQueue后并不会再次判断其deadlineNanos和当前时间的关系,不会再关注其是否过期。

3.3 处理NIO空轮询的bug

Java NIO在linux下基于epoll,但是因为poll和epoll对于突然中断的连接socket会对返回的eventSet事件集合置为EPOLLHUP或者EPOLLERR,eventSet事件集合发生了变化,这会导致Selector会被唤醒,唤醒之后却没有感兴趣的事件,导致IO事件处理的循环不会执行,陷入到循环中.

下面我们看看netty是如何处理此bug的

可以看到Netty通过重新构建Selector的方式去规避空轮询的bug,其中rebuildSelector最终调用rebuildSelector0,会将原本selector中的SelectionKey拷贝到新的selector,然后关闭旧的Selector

四丶总结

此节我们学习了NioEventLoop的执行原理,本质上还是通过Selector进行IO多路复用,理解了什么是事件循环,其中的事件指通过IO多路复用监听多路IO事件,循环是指循环的监听IO事件,并处理IO事件和其他任务,但是对于IO事件的处理我们并未做更多的学习,这部分将在下一篇中进行学习。

Netty源码学习2——NioEventLoop的执行的更多相关文章

  1. Netty源码分析之NioEventLoop(三)—NioEventLoop的执行

    前面两篇文章Netty源码分析之NioEventLoop(一)—NioEventLoop的创建与Netty源码分析之NioEventLoop(二)—NioEventLoop的启动中我们对NioEven ...

  2. 【Netty源码解析】NioEventLoop

    上一篇博客[Netty源码学习]EventLoopGroup中我们介绍了EventLoopGroup,实际说来EventLoopGroup是EventLoop的一个集合,EventLoop是一个单线程 ...

  3. Netty 源码学习——EventLoop

    Netty 源码学习--EventLoop 在前面 Netty 源码学习--客户端流程分析中我们已经知道了一个 EventLoop 大概的流程,这一章我们来详细的看一看. NioEventLoopGr ...

  4. Netty 源码学习——客户端流程分析

    Netty 源码学习--客户端流程分析 友情提醒: 需要观看者具备一些 NIO 的知识,否则看起来有的地方可能会不明白. 使用版本依赖 <dependency> <groupId&g ...

  5. Netty源码学习系列之4-ServerBootstrap的bind方法

    前言 今天研究ServerBootstrap的bind方法,该方法可以说是netty的重中之重.核心中的核心.前两节的NioEventLoopGroup和ServerBootstrap的初始化就是为b ...

  6. 【Netty源码学习】ServerBootStrap

    上一篇博客[Netty源码学习]BootStrap中我们介绍了客户端使用的启动服务,接下来我们介绍一下服务端使用的启动服务. 总体来说ServerBootStrap有两个主要功能: (1)调用父类Ab ...

  7. 【Netty源码学习】DefaultChannelPipeline(三)

    上一篇博客中[Netty源码学习]ChannelPipeline(二)我们介绍了接口ChannelPipeline的提供的方法,接下来我们分析一下其实现类DefaultChannelPipeline具 ...

  8. 【Netty源码学习】ChannelPipeline(一)

    ChannelPipeline类似于一个管道,管道中存放的是一系列对读取数据进行业务操作的ChannelHandler. 1.ChannelPipeline的结构图: 在之前的博客[Netty源码学习 ...

  9. 【Netty源码学习】EventLoopGroup

    在上一篇博客[Netty源码解析]入门示例中我们介绍了一个Netty入门的示例代码,接下来的博客我们会分析一下整个demo工程运行过程的运行机制. 无论在Netty应用的客户端还是服务端都首先会初始化 ...

  10. mybatis源码学习:插件定义+执行流程责任链

    目录 一.自定义插件流程 二.测试插件 三.源码分析 1.inteceptor在Configuration中的注册 2.基于责任链的设计模式 3.基于动态代理的plugin 4.拦截方法的interc ...

随机推荐

  1. 前端学习 node 快速入门 系列 —— 事件循环

    事件循环 本篇将对以下问题进行讨论: 浏览器有事件循环,node 也有事件循环,两者有什么异同? node 核心特性(事件驱动和非阻塞 I/O )和事件循环有什么关系? node 中的高并发和高性能和 ...

  2. Manjaro linux 安装svn 并在文件管理器里显示相关图标

    需要先安装svn linux版打开终端执行 sudo pacman -S svn 安装完成后执行一下 svn --version 出现这个就说明svn已经安装完成了,这个时候我们可以执行 svn ch ...

  3. python mitmproxy抓包库

    一.简介 mitmproxy是一款用Python编写的支持HTTP(S)的中间人代理工具.它可以拦截.查看.修改.重放和保存HTTP/HTTPS流量 ,支持命令行界面和图形界面,可用于安全测试.网络调 ...

  4. 沉痛悼念 pip search 一路走好

    不知道最近大家有没有发现在使用 pip search 的时候,总是出现一个 XMLRPC 的报错. $ pip search xlrdERROR: XMLRPC request failed [cod ...

  5. vue中的数据代理

    原理:通过vm对象来代理 Vue 中我们自己定义在data中的数据,首先: 我们自己定义的data中的对象或者属性 都会存储到vm中的_data 中进行数据劫持其次: 通过Object.defineP ...

  6. 【HarmonyOS】详解低代码端云一体化开发之数据模型

    [关键字] 元服务.低代码平台.端云一体化开发.数据模型.拖拽式UI [1.写在前面] 上一篇中分享了关于低代码平台开发元服务的基本使用,有兴趣的可以看一下,文章地址如下: https://devel ...

  7. C++面试八股文:聊一聊指针?

    某日二师兄参加XXX科技公司的C++工程师开发岗位第17面: 面试官:聊一聊指针? 二师兄:好的. 面试官:你觉得指针本质上是什么? 二师兄:这要从内存地址开始说起了.如果有一块容量是1G的内存,假设 ...

  8. Terraform 系列-使用 for-each 对本地 json 进行迭代

    系列文章 Terraform 系列文章 Grafana 系列文章 概述 前文 Grafana 系列 - Grafana Terraform Provider 基础 介绍了使用 Grafana Terr ...

  9. Kubernetes(k8s) Web-UI界面(二):部署和访问Kuboard

    目录 一.系统环境 二.前言 三.Kuboard简介 四.部署Kuboard 五.访问kuboard 六.总结 七.附加信息 一.系统环境 本文主要基于Kubernetes1.21.9和Linux操作 ...

  10. java.lang.Error: Unresolved compilation problems

    一般有两种常见的情况: 1.当一个 jar 文件的 MANIFEST.MF 中已经标记了 Sealed: true 时,这个 jar 内所有的 java package 中的类必须来自这个 jar 包 ...