1. 我们先来分析NioEventLoop执行普通任务runAllTasks(timeout)方法。内部第1行fetchFromScheduledTaskQueue()方法首先尝试从调度队列中获取已经到期需要执行的定时任务,并加入普通任务队列。
    • 如果此时普通任务队列已满,则重新置入调度队列,等待下一次轮训处理。因此,对于调度任务,执行时间未必一定是指定的时间。
    • 每次从调度队列中获取时只会判断第一个任务是否到达执行时间。如果多个任务都到了执行时间,后续到达时间的任务将在下次loop中获取。
private boolean fetchFromScheduledTaskQueue() {
    if (scheduledTaskQueue == null || scheduledTaskQueue.isEmpty()) {
        return true;
    }
    long nanoTime = AbstractScheduledEventExecutor.nanoTime();
    for (;;) {
        Runnable scheduledTask = pollScheduledTask(nanoTime);
        if (scheduledTask == null) {
            return true;
        }
        if (!taskQueue.offer(scheduledTask)) {
            scheduledTaskQueue.add((ScheduledFutureTask<?>) scheduledTask);
            return false;
        }
    }
}
  1. 接下来第2行即从普通队列中获取任务。如果获取到任务,则在safeExecute(task)方法中安全执行,之所以称之为安全执行是因为内部任务运行通过try{}catch{}包裹,防止某个任务执行时抛出异常,影响后续任务的执行。执行完后继续获取下一个普通任务继续执行。直到普通队列中的任务执行完毕或超过了入参timeout时则返回。需要注意的时,这里探测是否超出timeout时间是每64个任务检查一次。所以,如果入参timeout=0,则会至少执行64个任务。
protected boolean runAllTasks(long timeoutNanos) {
    fetchFromScheduledTaskQueue(); // 尝试从调度队列中获取到期的任务,加入普通队列。
    Runnable task = pollTask();
    if (task == null) {
        afterRunningAllTasks();
        return false;
    }
    final long deadline = timeoutNanos > 0 ? ScheduledFutureTask.nanoTime() + timeoutNanos : 0;
    long runTasks = 0;
    long lastExecutionTime;
    for (;;) {
        safeExecute(task) { 
            try {
                task.run();
            } catch (Throwable t) {
                logger.warn("A task raised an exception. Task: {}", task, t);
            }
        } 
        runTasks ++;
        if ((runTasks & 0x3F) == 0) {
            lastExecutionTime = ScheduledFutureTask.nanoTime();
            if (lastExecutionTime >= deadline) {
                break;
            }
        }
        task = pollTask();
        if (task == null) {
            lastExecutionTime = ScheduledFutureTask.nanoTime();
            break;
        }
    }
    afterRunningAllTasks();
    this.lastExecutionTime = lastExecutionTime;
    return true;
}
  1. 每次执行完任务后,都会执行afterRunningAllTasks()方法。
protected void afterRunningAllTasks() {
    runAllTasksFrom(tailTasks);
}
protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
    Runnable task = pollTaskFrom(taskQueue);
    if (task == null) {
        return false;
    }
    for (;;) {
        safeExecute(task);
        task = pollTaskFrom(taskQueue);
        if (task == null) {
            return true;
        }
    }
}