分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 技术分享

Netty 源码 NioEventLoop(三)执行过程

发布时间:2023-09-06 02:26责任编辑:傅花花关键词:暂无标签

Netty 源码 NioEventLoop(三)执行过程

Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html)

上文提到在启动 NioEventLoop 线程时会执行 SingleThreadEventExecutor#doStartThread(),在这个方法中调用 SingleThreadEventExecutor.this.run(),NioEventLoop 重写了 run() 方法。

@Overrideprotected void run() { ???for (;;) { ???????try { ???????????// 1. select 策略选择 ???????????switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) { ???????????????// 1.1 非阻塞的 select 策略。实际上,默认情况下,不会返回 CONTINUE 的策略 ???????????????case SelectStrategy.CONTINUE: ???????????????????continue; ???????????????// 1.2 阻塞的 select 策略 ???????????????case SelectStrategy.SELECT: ???????????????????select(wakenUp.getAndSet(false)); ???????????????????if (wakenUp.get()) { ???????????????????????selector.wakeup(); ???????????????????} ???????????????// 1.3 不需要 select,目前已经有可以执行的任务了 ???????????????default: ???????????} ???????????// 2. 执行网络 IO 事件和任务调度 ???????????cancelledKeys = 0; ???????????needsToSelectAgain = false; ???????????final int ioRatio = this.ioRatio; ???????????if (ioRatio == 100) { ???????????????try { ???????????????????// 2.1. 处理网络 IO 事件 ???????????????????processSelectedKeys(); ???????????????} finally { ???????????????????// 2.2. 处理系统 Task 和自定义 Task ???????????????????runAllTasks(); ???????????????} ???????????} else { ???????????????// 根据 ioRatio 计算非 IO 最多执行的时间 ????????????????final long ioStartTime = System.nanoTime(); ???????????????try { ???????????????????processSelectedKeys(); ???????????????} finally { ???????????????????final long ioTime = System.nanoTime() - ioStartTime; ???????????????????runAllTasks(ioTime * (100 - ioRatio) / ioRatio); ???????????????} ???????????} ???????} catch (Throwable t) { ???????????handleLoopException(t); ???????} ???????// 3. 关闭线程 ???????try { ???????????if (isShuttingDown()) { ???????????????closeAll(); ???????????????if (confirmShutdown()) { ???????????????????return; ???????????????} ???????????} ???????} catch (Throwable t) { ???????????handleLoopException(t); ???????} ???}}

NioEventLoop#run() 做了记下事情:

  1. 根据 selectStrategy 执行不同的策略
  2. 执行网络 IO 事件和任务调度
  3. 关闭线程

一、IO 轮询策略

(1) hasTasks

首先,在 run 方法中,第一步是调用 hasTasks() 方法来判断当前任务队列中是否有任务

protected boolean hasTasks() { ???assert inEventLoop(); ???return !taskQueue.isEmpty();}

这个方法很简单,仅仅是检查了一下 taskQueue 是否为空。至于 taskQueue 是什么呢,其实它就是存放一系列的需
要由此 EventLoop 所执行的任务列表。关于 taskQueue,我们这里暂时不表,等到后面再来详细分析它。

(2) DefaultSelectStrategy

// NioEventLoop#selectNowSupplierprivate final IntSupplier selectNowSupplier = new IntSupplier() { ???@Override ???public int get() throws Exception { ???????return selectNow(); ???}};// 非阻塞的 select 策略。实际上,默认情况下,不会返回 CONTINUE 的策略SelectStrategy.SELECT = -1;// 阻塞的 select 策略SelectStrategy.CONTINUE = -2;// DefaultSelectStrategy public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception { ???return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;}

显然当 taskQueue 为空时,执行的是 select(oldWakenUp) 方法。那么 selectNow() 和 select(oldWakenUp) 之间有什么区别呢? 来看一下,selectNow() 的源码如下

(3) selectNow

int selectNow() throws IOException { ???try { ???????return selector.selectNow(); ???} finally { ???????// restore wakeup state if needed ???????if (wakenUp.get()) { ???????????selector.wakeup(); ???????} ???}}

调用 JDK 底层的 selector.selectNow()。selectNow() 方法会检查当前是否有就绪的 IO 事件,如
果有,则返回就绪 IO 事件的个数;如果没有,则返回 0。注意,selectNow() 是立即返回的,不会阻塞当前线程。当
selectNow() 调用后,finally 语句块中会检查 wakenUp 变量是否为 true,当为 true 时,调用 selector.wakeup() 唤
醒 select() 的阻塞调用。

(4) select(boolean oldWakenUp)

private void select(boolean oldWakenUp) throws IOException { ???Selector selector = this.selector; ???try { ???????int selectedKeys = selector.select(timeoutMillis); ???} catch (CancelledKeyException e) { ???}}

在这个 select 方法中,调用了 selector.select(timeoutMillis),而这个调用是会阻塞住当前线程的,timeoutMillis
是阻塞的超时时间。到来这里,我们可以看到,当 hasTasks() 为真时,调用的的 selectNow() 方法是不会阻塞当前线
程的,而当 hasTasks() 为假时,调用的 select(oldWakenUp) 是会阻塞当前线程的。这其实也很好理解:
taskQueue 中没有任务时,那么 Netty 可以阻塞地等待 IO 就绪事件。而当 taskQueue 中有任务时,我们自然地希望
所提交的任务可以尽快地执行
,因此 Netty 会调用非阻塞的 selectNow() 方法,以保证 taskQueue 中的任务尽快可
以执行。


每天用心记录一点点。内容也许不重要,但习惯很重要!

Netty 源码 NioEventLoop(三)执行过程

原文地址:https://www.cnblogs.com/binarylei/p/10138638.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved