Netty 源码解析 ——— NioEventLoop 详解


原博文,点击这里

1.NioEventLoop

设计的两大功能:
1、是作为 IO 线程, 执行与 Channel 相关的 IO 操作, 包括 调用 select 等待就绪的 IO 事件、读写数据与数据的处理等;

2、第二个任务是作为任务队列执行任务, 任务可以分为2类:

2.1、普通task:通过调用NioEventLoop的execute(Runnable task)方法往任务队列里增加任务,Netty有很多系统task,创建他们的主要原因是:当io线程和用户线程同时操作网络资源的时候,为了防止并发操作导致的锁竞争,将用户线程的操作封装成Task放入消息队列中,由i/o线程负责执行,这样就实现了局部无锁化。
  2.2、定时任务:执行schedule()方法
  参考博文,点击这里


每个NioEventLoop里都有一个selector与TaskQueue,当我们在进行一些耗时的操作的时候,会产生阻塞,这时候我们就可以用到TaskQueue
通过前面的学习,我们对NioEventLoop做过如下几点简单的概述:
① NioEventLoop是一个基于JDK NIO的异步事件循环类,它负责处理一个Channel的所有事件在这个Channel的生命周期期间。
② NioEventLoop的整个生命周期只会依赖于一个单一的线程来完成。一个NioEventLoop可以分配给多个Channel,NioEventLoop通过JDK Selector来实现I/O多路复用,以对多个Channel进行管理。
如果调用Channel操作的线程是EventLoop所关联的线程,那么该操作会被立即执行。否则会将该操作封装成任务放入EventLoop的任务队列中。
④ 所有提交到NioEventLoop的任务都会先放入队列中,然后在线程中以有序(FIFO)/连续的方式执行所有提交的任务。
⑤ NioEventLoop的事件循环主要完成了:a)已经注册到Selector的Channel的监控,并在感兴趣的事件可执行时对其进行处理;b)完成任务队列(taskQueue)中的任务,以及对可执行的定时任务和周期性任务的处理(scheduledTaskQueue中的可执行的任务都会先放入taskQueue中后,再从taskQueue中依次取出执行)。

其中几点已经在启动流程的源码分析中做了详细的介绍。本文主要针对NioEventLoop事件循环的流程对NioEventLoop进行更深一步的学习。

2.重要属性

2.1taskQueue

用于存储任务的队列,是一个MpscUnboundedArrayQueue实例。

private final Queue<Runnable> taskQueue;

2.2tailTasks

是一个MpscUnboundedArrayQueue实例。用于存储当前或下一次事件循环(eventloop)迭代结束后需要执行的任务。

private final Queue<Runnable> tailTasks;

2.3scheduledTaskQueue

定时或周期任务队列,是一个PriorityQueue实例。

Queue<ScheduledFutureTask<?>> scheduledTaskQueue;

2.4 SELECTOR_AUTO_REBUILD_THRESHOLD

private static final int MIN_PREMATURE_SELECTOR_RETURNS = 3;
private static final int SELECTOR_AUTO_REBUILD_THRESHOLD;
int selectorAutoRebuildThreshold = SystemPropertyUtil.getInt("io.netty.selectorAutoRebuildThreshold", 512);
if (selectorAutoRebuildThreshold < MIN_PREMATURE_SELECTOR_RETURNS) {
    selectorAutoRebuildThreshold = 0;
}
SELECTOR_AUTO_REBUILD_THRESHOLD = selectorAutoRebuildThreshold;

SELECTOR_AUTO_REBUILD_THRESHOLD用于标识Selector空轮询的阈值,当超过这个阈值的话则需要重构Selector。
如果有设置系统属性”io.netty.selectorAutoRebuildThreshold”,并且该属性值大于MIN_PREMATURE_SELECTOR_RETURNS(即,3),那么该属性值就为阈值;如果该属性值小于MIN_PREMATURE_SELECTOR_RETURNS(即,3),那么阈值为0。如果没有设置系统属性”io.netty.selectorAutoRebuildThreshold”,那么阈值为512,即,默认情况下阈值为512。

2.5selectNowSupplier

private final IntSupplier selectNowSupplier = new IntSupplier() {
    @Override
    public int get() throws Exception {
        return selectNow();
    }
};

selectNow提供器,在事件循环里用于选择策略(selectStrategy)中。

2.6pendingTasksCallable

private final Callable<Integer> pendingTasksCallable = new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        return NioEventLoop.super.pendingTasks();
    }
};
@Override
public int pendingTasks() {
    // As we use a MpscQueue we need to ensure pendingTasks() is only executed from within the EventLoop as
    // otherwise we may see unexpected behavior (as size() is only allowed to be called by a single consumer).
    // See https://github.com/netty/netty/issues/5297
    if (inEventLoop()) {
        return super.pendingTasks();
    } else {
        return submit(pendingTasksCallable).syncUninterruptibly().getNow();
    }
}

因为pendingTasks()方法的底层就是调用taskQueue.size()方法,而前面我们已经说了taskQueue是一个MpscQueue,所以只能由EventLoop所在的线程来调用这个pendingTasks()方法,如果当前线程不是EventLoop所在线程,那么就将pendingTasks()封装在一个Callable(即,pendingTasksCallable)提交到taskQueue中去执行,并同步的等待执行的结果。

静态代码块

// Workaround for JDK NIO bug.
//
// See:
// - http://bugs.sun.com/view_bug.do?bug_id=6427854
// - https://github.com/netty/netty/issues/203
static {
    final String key = "sun.nio.ch.bugLevel";
    final String buglevel = SystemPropertyUtil.get(key);
    if (buglevel == null) {
        try {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                @Override
                public Void run() {
                    System.setProperty(key, "");
                    return null;
                }
            });
        } catch (final SecurityException e) {
            logger.debug("Unable to get/set System Property: " + key, e);
        }
    }

    int selectorAutoRebuildThreshold = SystemPropertyUtil.getInt("io.netty.selectorAutoRebuildThreshold", 512);
    if (selectorAutoRebuildThreshold < MIN_PREMATURE_SELECTOR_RETURNS) {
        selectorAutoRebuildThreshold = 0;
    }

    SELECTOR_AUTO_REBUILD_THRESHOLD = selectorAutoRebuildThreshold;

    if (logger.isDebugEnabled()) {
        logger.debug("-Dio.netty.noKeySetOptimization: {}", DISABLE_KEYSET_OPTIMIZATION);
        logger.debug("-Dio.netty.selectorAutoRebuildThreshold: {}", SELECTOR_AUTO_REBUILD_THRESHOLD);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值