Easy Netty 系列(七):EventLoop

EventLoop

EventLoop 是 Netty 的工作线程,EventLoop 是单线程的,每一个 EventLoop 永远只和一个 Java 线程绑定,这使得 EventLoop 处理读写事件是线程安全的(非共享 Handler)。

Netty 版本:4.1.70.Final

EventLoop 类结构

EventLoop类结构

无论是 EpollEventLoop、NioEventLoop、KQueueEventLoop 都是直接接触 SingleThreadEventLoop 实现的,这个类也再次验证了 EventLoop 是单线程的。

类、接口主要作用

名字 类型 作用
Executor 接口 主要定义一个可执行的 execute 方法
ExecutorService 接口 定义了对任务(Task)的控制方法,如提交(submit)、结束(shutdown)和状态方法(isShutdown)等
ScheduledExecutorService 接口 定义了定时类任务提交方法,特点是方法入参须传入时间和时间单位
AbstractExecutorService 抽象类 默认实现了 ExecutorService 的方法
EventExecutorGroup 接口 定义了组 Executor 的操作方法,核心方法是 next 用于返回一个组管理的 Executor。
EventLoopGroup 接口 特殊的 EventExecutorGroup,允许注册 Channel,用于选择 Channel
EventExecutor 接口 定义了一些方法,检测线程是否在 EventLoop 中运行
AbstractEventExecutor 抽象类 默认 EventExecutor 接口的实现
AbstractScheduledEventExecutor 抽象类 支持定时任务的 EventExecutor 接口的默认实现
SingleThreadEventExecutor 抽象类 单线程 EventExecutor 的默认实现,单线程 Executor 基类
EventLoop 接口 定义获取父 EventLoop 的方法 parent
SingleThreadEventLoop 抽象类 EventLoop 的抽象基类,它在单个线程中执行所有提交的任务。
NioEventLoop 聚合 Nio Selector 对象的类
EpollEventLoop 聚合 Epoll fd、Epoll event 的类

EventLoop 核心源码分析

AbstractScheduledEventExecutor

ScheduledEventExecutor 的核心功能是创建执行执行定时任务,这些功能对应的方法是:

public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

上边的这些方法最后都会调用一个私有的schedule方法,这个方法是 ScheduledEventExecutor 的核心。

    /**
     * 核心方法,所有暴露的schedule方法最后都调用此方法
     * @param task 可执行的对象(实现Runnable)且具有返回值(实现Future)
     * @return task执行结果,可获取执行结果(success/failure),可以监听状态
     */
    private <V> ScheduledFuture<V> schedule(final ScheduledFutureTask<V> task) {
        // 判断在哪里创建(schedule)定时任务
        if (inEventLoop()) {
            // 在EventLoop线程中
            // 如果是在EventLoop(handler执行上下文)中创建的定时任务,就放到任务执行队列中
            scheduleFromEventLoop(task);
        } else {
            // 在外部线程 e.g. main线程调用schedule创建定时任务

            // 截止时间 (当前 - ScheduleFutureTask创建时间)
            final long deadlineNanos = task.deadlineNanos();
            // 任务提交前回调判断,true 立即执行任务,false 延迟执行
            if (beforeScheduledTaskSubmitted(deadlineNanos)) {
                // execute表示调用执行(立即run),是个未实现的方法,未来由子类实现,由父类调用
                execute(task);
            } else {
                // 在不重写父类lazyExecute时默认仍然使用当前EventLoop线程执行
                lazyExecute(task);
                // 任务提交之后回调,方法返回true唤醒当前EventLoop线程,false不唤醒
                if (afterScheduledTaskSubmitted(deadlineNanos)) {
                    // 官方解释是为了避免线程竞争
                    // WAKEUP_TASK这个任务run方法没有执行的语句,使线程保持活跃(等待->可执行,持有CPU资源),避免线程竞争CPU开销
                    execute(WAKEUP_TASK);
                }
            }
        }
        return task;
    }
    // 在EventLoop中创建的定时任务放在taskQueue, 方便EventGroup调度
	final void scheduleFromEventLoop(final ScheduledFutureTask<?> task) {
        // nextTaskId a long and so there is no chance it will overflow back to 0
        scheduledTaskQueue().add(task.setId(++nextTaskId));
    }

SingleThreadEventExecutor

这个类主要实现了任务的启动、执行、结束

private void doStartThread();
// 执行一个任务
public void execute(Runnable task);
// 关闭
public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit);

SingleThreadEventLoop

SingleThreadEventLoop 是 EventLoop 的抽象基类,且继承了 SingleThreadEventExecutor,这个类的主要作用是通过构造器组装父类需要的属性。

NioEventLoop

这个类继承了 SingleThreadEventLoop,内部聚合 Nio Selector,作用是将 Channel 注册到 Selector 并且在事件循环中对这些进行多路复用。

    /**
     * The NIO {@link Selector}.
     */
    private Selector selector;
    private Selector unwrappedSelector;
    private SelectedSelectionKeySet selectedKeys;

EOF