Easy Netty 系列(七):EventLoop
EventLoop
EventLoop 是 Netty 的工作线程,EventLoop 是单线程的,每一个 EventLoop 永远只和一个 Java 线程绑定,这使得 EventLoop 处理读写事件是线程安全的(非共享 Handler)。
Netty 版本:4.1.70.Final
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