系列文章目录和关于我

零丶引入

在《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. 2021-01-28:redis使用过程中的注意事项有哪些?

    福哥答案2021-01-28: [答案1:](https://italk.mashibing.com/question/detail/ques_00005101)1.使用key值前缀来作命名空间虽然说 ...

  2. Django4全栈进阶之路14 项目实战(用户管理):base.html基础模板设计

    在 Django 中,我们可以使用模板继承来避免代码的重复.模板继承是指我们可以在一个模板中定义一些公共的 HTML 代码,然后在其他模板中继承这个基础模板,并根据需要添加或覆盖一些内容. 通常情况下 ...

  3. django--循环调用的解决办法

    不要导入该APP的包,而是加上双引号写入"App.xxx"

  4. phpstudy-sqlilabs-less-3

    题目:GET - Error based - Single quotes with twist 基于错误的单引号GET型变形注入 ?id=1 )and 1=2--+ ?id=1 "and 1 ...

  5. python爬虫防止IP被封的一些措施(转)

    python爬虫防止IP被封的一些措施(转) 在编写爬虫爬取数据的时候,因为很多网站都有反爬虫措施,所以很容易被封IP,就不能继续爬了.在爬取大数据量的数据时更是瑟瑟发抖,时刻担心着下一秒IP可能就被 ...

  6. nodejs和npm升级版本

    由于服务器环境的不同可能需要根据实际情况升降对应的nodejs 及npm 版本,最简单的例子就是 npx 只适用于 npm 5+ 看想用npx 那不升级咋办呢,还有如error eslint@7.16 ...

  7. python -----类反射

    #反射#描述:反射就是指在程序运行时,动态的去确定对象的类型,并且可以通过字符串的形式去调用对应的属性# ,方法,导入模块,是一种基于字符串的事情驱动# class User:# def __init ...

  8. 简单了解一下国产CPU

    这几天在B站.油管上刷了一些国产芯片真实上手视频,顺便自己也梳理一下芯片的一些基本概念,以及在美国科技制裁和围堵的情况下,国产CPU的发展情况.文末有我整理的一张思维导图,hope u find it ...

  9. shell编程-文件归档

    需求说明:设置定时任务,每天凌晨1点进行将指定目录(/root/scripts)下文件按照archive_目录名_年月日.tar.gz的格式归档存放到/root/archive 路径下. 1.编写脚本 ...

  10. gateway异常:DefaultDataBuffer cannot be cast to org.springframework.core.io.buffer.NettyDataBuffer

    启动gateway后 出现java.lang.ClassCastException: org.springframework.core.io.buffer.DefaultDataBufferFacto ...