JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor

时间:2022-09-21 10:00:31

JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor。它主要用来在给定的延迟之后运行任务,或者定期执行任务。ScheduledThreadPoolExecutor 的功能与 Timer 类似,但 Timer 对应的是单个后台线程,而 ScheduledThreadPoolExecutor 可以在构造函数中指定多个对应的后台线程数。

  1. JUC源码分析-线程池篇(三)Timer

1. ScheduledThreadPoolExecutor 简介

1.1 Timer 和 ScheduledThreadPoolExecutor 区别

Timer ScheduledThreadPoolExecutor
单线程 多线程
单个任务执行时间影响其他任务调度 多线程,不会影响
基于绝对时间 基于相对时间
一旦执行任务出现异常不会捕获,其他任务得不到执行 多线程,单个任务的执行不会影响其他线程

1.2 ScheduledThreadPoolExecutor 执行流程

ScheduledThreadPoolExecutor 的结构和 Timer 类似,也是由 DelayedWorkQueue、ThreadPoolExecutor、ScheduledFutureTask 三部分组成。DelayedWorkQueue 是一个*队列,所以 ThreadPoolExecutor 的 maximumPoolSize 在 ScheduledThreadPoolExecutor 中没有什么意义(设置 maximumPoolSize 的大小没有什么效果)。

ScheduledThreadPoolExecutor 的执行主要分为两大部分。

1)当调用 ScheduledThreadPoolExecutor#scheduleAtFixedRate() 方法或者 scheduleWithFixedDelay() 方法时,会向 ScheduledThreadPoolExecutor#DelayedWorkQueue 添加一个实现了 RunnableScheduledFutur 接口的 ScheduledFutureTask。

2)线程池中的线程从 DelayedWorkQueue 中获取 ScheduledFutureTask,然后执行任务。

JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor

2. ScheduledThreadPoolExecutor 源码分析

2.1 数据结构

JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor

2.2 定时任务调度 schedule

schedule、scheduleAtFixedRate、scheduleWithFixedDelay 只是将任务设置执行时间后添加到线程池队列中去了。

ublic 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;
}

2.3 任务执行 ScheduledFutureTask#run

public void run() {
    boolean periodic = isPeriodic();
    if (!canRunInCurrentRunState(periodic)) // 线程池关闭时是否断续执行定时任务
        cancel(false);
    else if (!periodic)     // 只执行一次
        ScheduledFutureTask.super.run();
    else if (ScheduledFutureTask.super.runAndReset()) { // 周期性执行
        setNextRunTime();               // 下一次执行时间 
        reExecutePeriodic(outerTask);   // 重新添加到任务队列中
    }
}

参考:

  1. 《深入理解Java线程池:ScheduledThreadPoolExecutor》:https://www.jianshu.com/p/925dba9f5969

每天用心记录一点点。内容也许不重要,但习惯很重要!