概述
ScheduledThreadPoolExecutor可以用来在给定延时后执行异步任务或者周期性执行任务,相对于任务调度的Timer来说,其功能更加强大,Timer只能使用一个后台线程执行任务,而ScheduledThreadPoolExecutor则可以通过构造函数来指定后台线程的个数。
该类通过以下特性实现了ThreadPoolExecutor的拓展:
- 使用自定义的FutureTask —— ScheduledFutureTask。
- 使用自定义队列 —— DelayedWorkQueue。它是一个无边界的DelayedQueue的变体。
- 支持可选的run-after-shutdown参数。可以重写shutdown方法,用以删除或者取消在执行shutdown方法后还没有运行的task。
- task的装饰方法,用以拦截和装饰。因为子类无法通过重写shubmit方法来获得这个效果。
ScheduledThreadPoolExecutor处理的task分为以下2种类型:
- periodic task:周期性执行的任务
- one-shot delayed task:延迟执行的一次性任务
源码分析
延迟执行delayed task的schedule方法
根据指定的时间延迟和时间单位,将task加入线程池延迟执行。
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
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;
}
处理periodic task的scheduleAtFixedRate方法
根据指定的时间延迟、时间周期和时间单位,将task加入线程池延迟执行。
该方法按指定频率周期执行某个任务。例如,初始化延迟0ms开始执行,每隔100ms重新执行一次任务。
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;
}
处理periodic task的scheduleWithFixedDelay方法
根据指定的初始时间延迟、时间间隔和时间单位,将task加入线程池延迟执行。
该方法按指定频率间隔执行某个任务。例如,初始化时延时0ms开始执行,本次执行结束后延迟100ms开始下次执行。
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;
}
delayedExecute()方法
处理delayed task或者periodic task的主要execute方法。如果线程池是shutdown的,拒绝task加入线程池,否则将线程池加入队列中,并启动一个线程,必要时执行它。如果在task加入队列后时线程池shut down了,根据run-after-shutdown参数和状态决定是否取消和删除这个task。
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();
}
}
ensurePrestart()方法
/**
* Same as prestartCoreThread except arranges that at least one
* thread is started even if corePoolSize is 0.
*/
void ensurePrestart() {
//获取线程池中的当前线程数
int wc = workerCountOf(ctl.get());
if (wc < corePoolSize)
addWorker(null, true);
else if (wc == 0)
addWorker(null, false);
}