源码篇-ScheduledThreadPoolExecutor之执行任务

一、schedule

public ScheduledFuture<?> schedule(Runnable command,
                                   long delay,
                                   TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    RunnableScheduledFuture<?> t = decorateTask(command,
        new ScheduledFutureTask<Void>(command, null,
                                      triggerTime(delay, unit)));
    delayedExecute(t);
    return t;
}


public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                       long delay,
                                       TimeUnit unit) {
    if (callable == null || unit == null)
        throw new NullPointerException();
    RunnableScheduledFuture<V> t = decorateTask(callable,
        new ScheduledFutureTask<V>(callable,
                                   triggerTime(delay, unit)));
    delayedExecute(t);
    return t;
}
  • 不同的地方在于一个传入的是Runnable类型,一个传入的是Callable<V>类型,但是Runnable类型最终也会转为Callable类型
  • triggerTime是根据delay计算任务的执行时间
private void delayedExecute(RunnableScheduledFuture<?> task) {
    // 如果线程池关闭了,拒绝任务
    if (isShutdown())
        reject(task);
    else {
        // 将任务加入到队列
        super.getQueue().add(task);
        // 再判断线程池状态
        if (isShutdown() &&
            !canRunInCurrentRunState(task.isPeriodic()) &&
            remove(task))
            task.cancel(false);
        // 启动任务
        else
            ensurePrestart();
    }
}

void ensurePrestart() {
    // 获取工作线程数
    int wc = workerCountOf(ctl.get());
    // 启动核心线程
    if (wc < corePoolSize)
        // 因为这里是定时任务,所以这里firstTask为null
        addWorker(null, true);
    // 启动非核心线程
    else if (wc == 0)
        addWorker(null, false);
}
  • 根据线程池状态判断是否取消任务
  • Worker只是启动线程,最终执行任务还是ScheduledFutureTask#run
public void run() {
    // 判断是不是周期性任务,period != 0 就是周期性任务
    boolean periodic = isPeriodic();
    // 根据线程池状态判断是否需要取消任务
    if (!canRunInCurrentRunState(periodic))
        cancel(false);
    // 如果是不是周期性任务,执行直接
    else if (!periodic)
        ScheduledFutureTask.super.run();
    // 如果是周期性任务,需要重置状态
    else if (ScheduledFutureTask.super.runAndReset()) {
        // 设置下一次执行的时间
        setNextRunTime();
        // 重新添加任务
        reExecutePeriodic(outerTask);
    }
}

二、scheduleAtFixedRate与scheduleWithFixedDelay

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                              long initialDelay,
                                              long period,
                                              TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    if (period <= 0)
        throw new IllegalArgumentException();
    ScheduledFutureTask<Void> sft =
        new ScheduledFutureTask<Void>(command,
                                      null,
                                      triggerTime(initialDelay, unit),
                                      unit.toNanos(period));
    RunnableScheduledFuture<Void> t = decorateTask(command, sft);
    sft.outerTask = t;
    delayedExecute(t);
    return t;
}


public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                 long initialDelay,
                                                 long delay,
                                                 TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    if (delay <= 0)
        throw new IllegalArgumentException();
    ScheduledFutureTask<Void> sft =
        new ScheduledFutureTask<Void>(command,
                                      null,
                                      triggerTime(initialDelay, unit),
                                      unit.toNanos(-delay));
    RunnableScheduledFuture<Void> t = decorateTask(command, sft);
    sft.outerTask = t;
    delayedExecute(t);
    return t;
}
  • scheduleAtFixedRate传入的period是正数,scheduleWithFixedDelay传入的period是负数
private void setNextRunTime() {
    long p = period;
    if (p > 0)
        time += p;
    else
        time = triggerTime(-p);
}

long triggerTime(long delay) {
    return now() +
        ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
  • 由于scheduleAtFixedRate传入的period为正数,所以下一个任务的执行时间是相对上个任务的开始时间
  • 由于scheduleWithFixedDelay传入的period为负数,所以下一个任务的执行时间是相对上个任务的结束时间
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容