运行任务来处理在连接的生命周期内发生的事件是任何网络框架的基本功能。与之相应的编程上的构造称为事件循环------Netty中的EventLoop便与之对应。事件循环的基本思想如下:
while (!terminated) {
List<Runnable> readyEvents = blockUtilEventsReady();
for (Runnable ev : readyEvents) {
ev.run();
}
}
上述事件循环中,首先会阻塞直到有事件已经就绪可被运行,然后遍历处理就绪的事件,之后再开始下一次事件循环。Netty中的EventLoop便是上述过程中的核心角色,它依赖于io.netty.util.concurrent包对并发的处理,而io.netty.util.concurrent包是构建在JDK的java.util.concurrent包上,用来提供ThreadExecutor。而io.netty.channel包中的类,为了与Channel的事件进行交互,扩展了这些接口/类。下图便是相关类的层次结构:
在这个模型中,一个EventLoop将由一个永远都不会改变的Thread驱动,同时任务(Runnable或者Callable)可以直接提交给EventLoop实现,以立即执行或者调度执行。根据配置和可以CPU核心的不同,可能会创建多个EventLoop实例用以优化资源的使用,并且单个EventLoop可能会被指派用于服务多个Channel。事件和任务的执行是以FIFO的顺序执行的,这样可以通过保证字节内容总是按照正确的顺序处理,消除潜在的数据损坏的可能性。
本篇文章先来看一下io.netty.util.concurrent包中EventExecutorGroup及其子类的实现机制。
一、EventExecutorGroup接口
EventExecutorGroup是netty线程池部分的顶层接口,该接口扩展了ScheduledExecutorService接口,添加了一些有用的方法。它通过next()方法来提供EventExecutor供使用,它也负责管理它们的生命周期,定义如下:
public interface EventExecutorGroup extends ScheduledExecutorService, Iterable<EventExecutor> {
/**
* 只有当该Group所管理的所有EventExecutor全部shutdownGracefully才会返回true
*/
boolean isShuttingDown();
/**
* 关闭Group, 默认参数
*/
Future<?> shutdownGracefully();
/**
* 发起关闭executor.一旦该方法被调用,isShuttingDown方法就会返回true。
* 该方法可以确保在quiet period时间内没有新任务提交, 如果在quiet period时间内如果由新任务,
* 任务可以被接受,并会重新计算quiet period
*/
Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit);
/**
* 返回一个Future,当所管理的所有EventExecutor都被结束时会得到通知
*/
Future<?> terminationFuture();
/**
* 返回Group管理的其中一个EventExecutor
*/
EventExecutor next();
}
从定义可以看出,主要添加了一些优雅的关闭线程池的方法以及获取Executor的方法。
该接口有一个抽象实现类AbstractEventExecutorGroup,该类的实现方法是通过调用next()方法获取一个EventExecutor,然后由EventExecutor进行执行,如submit方法的实现:
public Future<?> submit(Runnable task) {
return next().submit(task); //next()获取EventExecutor,并提交给它执行
}
二、EventExecutor
EventExecutor是一种特殊的EventExecutorGroup,它有一些方法用于判断一个线程是否就是事件循环中绑定的线程。定义如下:
public interface EventExecutor extends EventExecutorGroup {
/**返回指向自己的引用
* Returns a reference to itself.
*/
@Override
EventExecutor next();
/**
* 返回它所属的EventExecutorGroup
*/
EventExecutorGroup parent();
/**
* 调用inEventLoop(Thread)方法,以Thread.currentThread()作为参数
*/
boolean inEventLoop();
/**
* 如果给定的线程就是事件循环的执行线程会返回true,否则返回false
*/
boolean inEventLoop(Thread thread);
/**
* Return a new {@link Promise}.
*/
<V> Promise<V> newPromise();
/**
* Create a new {@link ProgressivePromise}.
*/
<V> ProgressivePromise<V> newProgressivePromise();
/**
* 创建一个已经标记为成功/失败的Future. 因此isSuccess()方法会试中返回true/false
* 所有的listener会直接得到通知.所有阻塞方法的调用都不会阻塞。
*/
<V> Future<V> newSucceededFuture(V result);
<V> Future<V> newFailedFuture(Throwable cause);
}
该接口也有一个抽象实现类AbstractEventExecutor,非常简单,它有两个默认值:
static final long DEFAULT_SHUTDOWN_QUIET_PERIOD = 2;
static final long DEFAULT_SHUTDOWN_TIMEOUT = 15;
也就是shutdownGracefully的两个参数的默认值。
三、DefaultEventExecutorGroup:EventExecutorGroup接口的默认实现
该类继承了MultithreadEventExecutorGroup类,提供了EventExecutorGroup的默认实现,核心内容都在MultithreadEventExecutorGroup里,该类只是封装了几个构造方法,而构造方法也是调用父类的构造方法。
1、我们先来看一下该类的基本属性:
private final EventExecutor[] children; //所管理的EventExecutor
private final Set<EventExecutor> readonlyChildren; //只读的EventExecutor
private final AtomicInteger terminatedChildren = new AtomicInteger(); //已结束的EventExecutor数量
//用于通知完成关闭的Future
private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
//用于从Group中选择下一个EventExecutor
private final EventExecutorChooserFactory.EventExecutorChooser chooser;
上面的属性中的chooser用于从Group中选取下一个EventExecutor。接口定义如下:
public interface EventExecutorChooserFactory {
/**
* 返回新的EventExecutorChooser
*/
EventExecutorChooser newChooser(EventExecutor[] executors);
/**
* Chooses the next {@link EventExecutor} to use.
*/
interface EventExecutorChooser {
/**
* 返回下一个EventExecutor.
*/
EventExecutor next();
}
}
默认实现类如下:
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {
//静态实例,由构造方法创建
public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();
//构造方法
private DefaultEventExecutorChooserFactory() { }
//创建一个新的EventExecutorChooser
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) { //如果是2的幂
return new PowerOfTwoEventExecutorChooser(executors);
} else { //如果EventExecutor的数量不是2的幂,则选用下面的策略
return new GenericEventExecutorChooser(executors);
}
}
//两种next策略
private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
//构造方法,初始化executors属性
PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
//以不断自增并对数量取模的方式轮询获取下一个EventExecutor
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
}
private static final class GenericEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
GenericEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
//直接进行取模运算
@Override
public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
}
}
从默认实现类可以看出,有两种next()的实现方式,它们都是round-robin式的,也就是对索引自增然后对数量取模来轮询获取下一个。但是该类针对数量为2的幂的Group采用&运算代替了取模运算%,加快速度。
2、构造方法
/**
* @param nThreads 该Group使用的线程数目
* @param threadFactory 使用的ThreadFactory
* @param maxPendingTasks 在新的task被拒绝执行前等待执行的最大task数目.
* @param rejectedHandler 拒绝策略
*/
public DefaultEventExecutorGroup(int nThreads, ThreadFactory threadFactory, int maxPendingTasks,
RejectedExecutionHandler rejectedHandler) {
super(nThreads, threadFactory, maxPendingTasks, rejectedHandler); //调用父类构造方法
}
构造方法就是初始化上述几个属性,不再详述。
四、SingleThreadEventExecutor实现
该类是EventExecutor的特殊实现,它内部只有一个线程来执行任务,该类封装了一个Thread类型的成员变量,代表执行线程。
1、我们先来看一下它的构造方法:
/**
* @param parent 所属的EventExecutorGroup
* @param executor 用于执行的Executor
* @param addTaskWakesUp 该参数为true时,只有addTask方法可以唤醒执行线程
* @param maxPendingTasks 拒绝任务前可以等待执行的最大任务数
* @param rejectedHandler 拒绝策略.
*/
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedHandler) {
super(parent);
this.addTaskWakesUp = addTaskWakesUp;
this.maxPendingTasks = Math.max(16, maxPendingTasks); //至少16
this.executor = ThreadExecutorMap.apply(executor, this);
taskQueue = newTaskQueue(this.maxPendingTasks); //使用LinkedBlockingQueue
rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}
2、JDK中线程池各种执行任务的方法都是通过调用execute方法实现的,因此我们先看一下这个方法的实现:
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
//判断当前线程是否是执行线程
boolean inEventLoop = inEventLoop();
//向任务队列中添加该任务
addTask(task);
if (!inEventLoop) { //如果当前线程不是执行线程
startThread(); //如果当前线程还没启动,则启动该线程
if (isShutdown()) { //如果线程池关闭了,则拒绝执行并移除该任务
boolean reject = false;
try {
if (removeTask(task)) {
reject = true;
}
} catch (UnsupportedOperationException e) {
// The task queue does not support removal so the best thing we can do is to just move on and
// hope we will be able to pick-up the task before its completely terminated.
// In worst case we will log on termination.
}
if (reject) {
reject();
}
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}
//检查当前线程是不是内部的执行该线程thread
public boolean inEventLoop() {
return inEventLoop(Thread.currentThread());
}
public boolean inEventLoop(Thread thread) {
return thread == this.thread;
}
//向任务队列添加任务
protected void addTask(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
if (!offerTask(task)) { //如果任务添加失败,则拒绝该任务
reject(task);
}
}
final boolean offerTask(Runnable task) {
if (isShutdown()) { //如果线程池关闭了则抛出异常
reject();
}
return taskQueue.offer(task); //向任务队列添加,如果不能立即插入则返回false
}
可以看出execute方法主要就是将任务提交到任务队列。
3、我们再来看一下内部的一个执行队列中所有任务的方法:
//运行任务队列中的所有任务,至少执行了一个任务就会返回true
protected boolean runAllTasks() {
//首先确保当前线程就是执行线程
assert inEventLoop();
boolean fetchedAll;
boolean ranAtLeastOne = false;
//循环执行任务
do {
fetchedAll = fetchFromScheduledTaskQueue(); //从schedule队列获取定时任务至taskQueue
if (runAllTasksFrom(taskQueue)) { //运行taskQueue中的任务,true代表执行了至少一个任务
ranAtLeastOne = true;
}
} while (!fetchedAll); // 持续处理所有定时任务
if (ranAtLeastOne) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
}
afterRunningAllTasks();
return ranAtLeastOne; //返回是否已经执行了至少一个任务
}
//将定时任务队列中到期的任务放入taskQueue
private boolean fetchFromScheduledTaskQueue() {
//任务队列空了就会返回true
if (scheduledTaskQueue == null || scheduledTaskQueue.isEmpty()) {
return true;
}
long nanoTime = AbstractScheduledEventExecutor.nanoTime();
for (;;) {
//从定时任务队列获取任务
Runnable scheduledTask = pollScheduledTask(nanoTime);
if (scheduledTask == null) {
return true;
}
//将到期的定时任务放入taskQueue,如果放入失败则重新放回定时任务队列
if (!taskQueue.offer(scheduledTask)) {
// No space left in the task queue add it back to the scheduledTaskQueue so we pick it up again.
scheduledTaskQueue.add((ScheduledFutureTask<?>) scheduledTask);
return false;
}
}
}
//从taskQueue中获取任务来执行
protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
Runnable task = pollTaskFrom(taskQueue); //获取任务
if (task == null) {
return false; //如果没有任务就返回false
}
for (;;) { //循环获取任务并执行
safeExecute(task); //执行该任务,也就是调用run()方法
task = pollTaskFrom(taskQueue);
if (task == null) {
return true; //如果处理完了就返回true
}
}
}
从上述运行代码可以看出,SingleThreadEventExecutor中有两个任务队列,一个普通任务队列taskQueue,一个存放定时任务的队列scheduledTaskQueue,执行任务时,会不断的先将定时任务队列中到期的任务放入taskQueue,然后再批量执行taskQueue中的任务,直到scheduledTaskQueue中再没有任务。
4、关闭方法shutdownGracefully
public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
//参数检查
if (quietPeriod < 0) {
throw new IllegalArgumentException("quietPeriod: " + quietPeriod + " (expected >= 0)");
}
if (timeout < quietPeriod) {
throw new IllegalArgumentException(
"timeout: " + timeout + " (expected >= quietPeriod (" + quietPeriod + "))");
}
if (unit == null) {
throw new NullPointerException("unit");
}
//如果已经处于正关闭状态,则返回future等待通知就可以
if (isShuttingDown()) {
return terminationFuture();
}
boolean inEventLoop = inEventLoop();
boolean wakeup;
int oldState;
for (;;) {
if (isShuttingDown()) {
return terminationFuture();
}
int newState;
wakeup = true;
oldState = state;
if (inEventLoop) { //如果当前线程就是执行线程
newState = ST_SHUTTING_DOWN; //设置为正在关闭状态
} else {
switch (oldState) {
case ST_NOT_STARTED:
case ST_STARTED:
newState = ST_SHUTTING_DOWN;
break;
default:
newState = oldState;
wakeup = false;
}
}
if (STATE_UPDATER.compareAndSet(this, oldState, newState)) {
break;
}
}
gracefulShutdownQuietPeriod = unit.toNanos(quietPeriod);
gracefulShutdownTimeout = unit.toNanos(timeout);
if (ensureThreadStarted(oldState)) {
return terminationFuture;
}
if (wakeup) {
wakeup(inEventLoop);
}
return terminationFuture();
}