主要是三个步骤:
第一步,取出 IO 事件及对应的 Channel 。其中selectedKeys[i] = null;
的目的是防止内存泄漏
第二步,处理 Channel
if (a instanceof AbstractNioChannel) { processSelectedKey(k, (AbstractNioChannel) a);} else { @SuppressWarnings("unchecked") NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a; processSelectedKey(k, task);}Netty 的轮询注册机制其实是将 AbstractNioChannel 内部的 JDK 类 SelectableChannel 对象注册到 JDK 类 Selector 对象上,并且将 AbstractNioChannel 作为SelectableChannel 对象的一个 attachment 附属上,这样在 JDK 轮询出某条 SelectableChannel 有 IO 事件发生时,就可以直接取出 AbstractNioChannel 进行后续操作 。
在Netty的Channel中,有两大类型的Channel,
一个是NioServerSocketChannel,由boss NioEventLoopGroup负责处理;
一个是NioSocketChannel , 由worker NioEventLoop负责处理,
所以:
(1)对于boss NioEventLoop来说,轮询到的是连接事件,后续通过NioServerSocketChannel的Pipeline将连接交给一个worker NioEventLoop处理;
(2)对于worker NioEventLoop来说,轮询到的是读写事件,后续通过NioSocketChannel的Pipeline将读取到的数据传递给每个ChannelHandler来处理 。
第三步,判断是否需要再一次轮询
由needsToSelectAgain
变量控制 , needsToSelectAgain
变量在如下方法中被调用,在NioEventLoop
中
private static final int CLEANUP_INTERVAL = 256; void cancel(SelectionKey key) { key.cancel(); cancelledKeys ++; if (cancelledKeys >= CLEANUP_INTERVAL) { cancelledKeys = 0; needsToSelectAgain = true; } }cancel方法是用于将key取消 , 并且在被取消的key到达CLEANUP_INTERVAL
的时候,设置needsToSelectAgain
为 true,CLEANUP_INTERVAL
默认值为256 。
也就是说,对于每个NioEventLoop而言,每隔256个Channel从Selector上移除的时候,就标记needsToSelectAgain为true,然后将SelectedKeys的内部数组全部清空,方便JVM垃圾回收 , 然后调用selectAgain重新填装SelectionKeys数组 。
处理任务队列调用的是如下方法
protected boolean runAllTasks() { assert inEventLoop(); boolean fetchedAll; boolean ranAtLeastOne = false; do { fetchedAll = fetchFromScheduledTaskQueue(); if (runAllTasksFrom(taskQueue)) { ranAtLeastOne = true; } } while (!fetchedAll); // keep on processing until we fetched all scheduled tasks. if (ranAtLeastOne) { lastExecutionTime = getCurrentTimeNanos(); } afterRunningAllTasks(); return ranAtLeastOne; }主要流程如下:
1.NioEventLoop在执行过程中不断检测是否有事件发生,如果有事件发生就处理,处理完事件之后再处理外部线程提交过来的异步任务 。
2.在检测是否有事件发生的时候 , 为了保证异步任务的及时处理,只要有任务要处理,就立即停止事件检测,随即处理任务 。
3.外部线程异步执行的任务分为两种:定时任务和普通任务,分别落地到 MpscQueue 和 PriorityQueue , 而 PriorityQueue 中的任务最终都会填充到MpscQueue中处理 。
4.Netty每隔64个任务检查一次是否该退出任务循环 。
推荐阅读
- ZCTF note3:一种新解法
- 学习ASP.NET Core Blazor编程系列四——迁移
- 五 Netty 学习:服务端启动核心流程源码说明
- 【前端必会】走进webpack生命周期,另类的学习方法
- opencvcv.line
- 骰子五个点怎么玩(骰子五个六五个七怎么玩)
- 三十六 Java开发学习----SpringBoot三种配置文件解析
- 4 MySQL学习---MySQL索引
- 基础&进阶 线段树学习笔记(一) | P3372 【模板】线段树 1 题解
- 王者荣耀七周年击败特效怎么领取