目录
2、compareTo / getDelay / isPeriodic
2、schedule / scheduleAtFixedRate / scheduleWithFixedDelay
4、shutdown/ shutdownNow / onShutdown
本篇博客来详细探讨延期执行或者周期性执行任务的线程池ScheduledThreadPoolExecutor的实现细节。
一、ScheduledFutureTask
1、定义
ScheduledFutureTask是ScheduledThreadPoolExecutor的内部类,表示一个延期执行的任务,其类继承关系如下:
其中ScheduledFuture接口的定义如下:
Delayed接口的含义可以参考之前的《Java8 LinkedBlockingQueue和DelayQueue 源码解析》 。
RunnableScheduledFuture接口的定义如下:
该类包含的属性如下:
//原子递增生成的一个序列号
private final long sequenceNumber;
//执行该任务的开始时间,以纳秒为单位
private long time;
//重复执行下一次任务的间隔时间,单位是纳秒,如果是正值则表示是固定的速率执行
//如果是负值,则表示以固定的延时执行,如果0则表示不需要重复执行
private final long period;
//周期执行时将此实例再次添加到任务队列中,从而能够被再次执行
RunnableScheduledFuture<V> outerTask = this;
//用于保存当前实例在DelayedWorkQueue数组中的索引,方便从数组中移除的时候可以快速定位
int heapIndex;
该类的构造方法如下:
ScheduledFutureTask(Runnable r, V result, long ns) {
super(r, result);
this.time = ns;
this.period = 0;
//sequencer是ScheduledThreadPoolExecutor的属性
this.sequenceNumber = sequencer.getAndIncrement();
}
ScheduledFutureTask(Runnable r, V result, long ns, long period) {
super(r, result);
this.time = ns;
this.period = period;
this.sequenceNumber = sequencer.getAndIncrement();
}
ScheduledFutureTask(Callable<V> callable, long ns) {
super(callable);
this.time = ns;
this.period = 0;
this.sequenceNumber = sequencer.getAndIncrement();
}
2、compareTo / getDelay / isPeriodic
这三个方法用于实现RunnableScheduledFuture接口的
public long getDelay(TimeUnit unit) {
//获取剩余的有效期,大于0表示延时未到,不能执行
return unit.convert(time - now(), NANOSECONDS);
}
public int compareTo(Delayed other) {
if (other == this) // compare zero if same object
return 0;
if (other instanceof ScheduledFutureTask) {
ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
//比较两者的执行起始时间
long diff = time - x.time;
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
//起始时间一致,则比较序列号
else if (sequenceNumber < x.sequenceNumber)
return -1;
else
return 1;
}
//如果不是ScheduledFutureTask实例,则比较剩余的有效期
long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
//判断是否周期执行的任务
public boolean isPeriodic() {
return period != 0;
}
final long now() {
return System.nanoTime();
}
3、run / cancel
这两个方法改写了父类FutureTask的实现,其中run方法是实现任务周期性执行的核心,如下:
public boolean cancel(boolean mayInterruptIfRunning) {
//调用父类方法取消该任务
boolean cancelled = super.cancel(mayInterruptIfRunning);
//removeOnCancel是ScheduledThreadPoolExecutor的属性,默认为false
//heapIndex大于等于0说明该Task还在DelayedWorkQueue中
if (cancelled && removeOnCancel && heapIndex >= 0)
remove(this); //从任务队列中将其移除
return cancelled;
}
public void run() {
//是否周期执行的
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic)) //如果当前线程池不能执行该任务,则取消
cancel(false);
else if (!periodic) //非周期执行任务,调用父类的run方法
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) { //runAndReset方法正常执行后不保存结果,不更新状态
//重新计算下一次运行的起始时间
setNextRunTime();
//将outerTask提交到任务队列,outerTask通常就是this,从而实现周期性执行
reExecutePeriodic(outerTask);
}
}
boolean canRunInCurrentRunState(boolean periodic) {
return isRunningOrShutdown(periodic ?
continueExistingPeriodicTasksAfterShutdown :
executeExistingDelayedTasksAfterShutdown);
}
final boolean isRunningOrShutdown(boolean shutdownOK) {
int rs = runStateOf(ctl.get());
return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
}
private void setNextRunTime() {
long p = period;
if (p > 0) //固定速率的,不考虑执行任务本身的耗时
time += p;
else
//p小于0,固定延时的
time = triggerTime(-p);
}
long triggerTime(long delay) {
//当前时间加上固定延时,如果delay大于Long的最大值的一半,则走后面的overflowFree
return now() +
((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
private long overflowFree(long delay) {
Delayed head = (Delayed) super.getQueue().peek();
if (head != null) {
long headDelay = head.getDelay(NANOSECONDS);
if (headDelay < 0 && (delay - headDelay < 0))
delay = Long.MAX_VALUE + headDelay;
}
return delay;
}
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
if (canRunInCurrentRunState(true)) {
super.getQueue().add(task);//将该任务添加到任务队列中
//再次检查当前线程池是否可以执行任务,如果不能则将其从任务队列移除并取消掉
if (!canRunInCurrentRunState(true) && remove(task))
task.cancel(false);
else
//可以正常执行,尝试增加一个执行任务的线程
ensurePrestart();
}
}
二、DelayedWorkQueue
1、定义
DelayedWorkQueue是ScheduledThreadPoolExecutor的内部类,是一个先进先出的,自动扩容的且支持排序的阻塞队列,用于保存延迟执行的任务ScheduledFutureTask