java并发编程之美 学习笔记
ScheduledThreadPoolExecutor 是一个可以在指定延时时间后执行或定时执行的任务调度线程池.
ScheduledThreadPoolExecutor
ScheduledFutureTask
ScheduledThreadPoolExecutor 定义了一个重要的类ScheduledFutureTask
,首先对它进行分析.
首先看下它的类图。
它继承自FutureTask
同时还实现了RunnableScheduledFuture
等接口.
FutureTask
关于FutureTask相关参考:Callable、Future和FutureTask解析
RunnableScheduledFuture接口
public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> {
//是否周期性
boolean isPeriodic();
}
ScheduledFuture
它继承了Delayed, Future
接口,自身并没有定义任何方法.
ScheduledFutureTask
public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService {
//调用ScheduledFutureTask.cancel时,是否从queue中移除
private volatile boolean removeOnCancel = false;
//Sequence number
private static final AtomicLong sequencer = new AtomicLong();
private class ScheduledFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> {
//Sequence number
private final long sequenceNumber;
//nanoTime后,执行task
private long time;
/**
* 0: 说明当前任务是一次性的 ,执行完毕后就退出了 。
* 负数: 说明当前任务为 fixed-delay 任务,是固定延迟的定时可重复执行任务 。(任务结束时间+period,2period..... n * period)
* 正数: 说明当前任务为 fixed-rate 任务 ,是固定频率的定时可重复执行任务。执行时间为:(time + -period ,-2period ..... -n*period)
*/
private final long period;
//由reExecutePeriodic() 重新入队的任务.
RunnableScheduledFuture<V> outerTask = this;
//delay queue中的index,用于快速取消
int heapIndex;
ScheduledFutureTask(Runnable r, V result, long ns) {
super(r, result);
this.time = ns;
this.period = 0;
this.sequenceNumber = sequencer.getAndIncrement();
}
//ScheduledFutureTask()重载构造函数略.....
public long getDelay(TimeUnit unit) {
return unit.convert(time - now(), NANOSECONDS);
}
//按照time 或者getDelay() asc排序;
public int compareTo(Delayed other) {
//略..
}
public boolean isPeriodic() {
// period!=0 表示为周期性任务
return period != 0;
}
//周期性任务,设置下一次执行的时间
private void setNextRunTime() {
long p = period;
if (p > 0)
//p>0 ,按照固定频率执行. 执行时间为:time+ (period ,2period ..... n*period)
time += p;
else
//p<0 , 按照固定延时执行. 执行时间为:执行完成时间+ (period ,2period ..... n*period)
time = triggerTime(-p);
}
public boolean cancel(boolean mayInterruptIfRunning) {
boolean cancelled = super.cancel(mayInterruptIfRunning);
if (cancelled && removeOnCancel && heapIndex >= 0)
//从workQueue 任务队列中移除task;
remove(this);
return cancelled;
}
public void run() {
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))
//不允许执行时,取消任务
cancel(false);
else if (!periodic)
//如果不是周期性任务, 则直接调用super.run();
ScheduledFutureTask.super.run();
//ScheduledFutureTask.super.runAndReset() 调用callable.run()执行任务;
//执行成功后,重新设置state==NEW,然后将任务计算下次执行时间后重新入列
else if (ScheduledFutureTask.super.runAndReset()) {
//设置下一次执行时间;
setNextRunTime();
//2.重新入队
reExecutePeriodic(outerTask);
}
}
}
final long now() {
return System.nanoTime();
}
//1.计算下一次触发事件;
long triggerTime(long delay) {
return now() +
((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
//2.
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
if (canRunInCurrentRunState(true)) {
//重新入队
super.getQueue().add(task);
if (!canRunInCurrentRunState(true) && remove(task))
task.cancel(false);
else
//调用ThreadPoolExecutor方法(),确保至少有一个worker线程.
ensurePrestart();
}
}
}
ScheduledThreadPoolExecutor
构造函数
public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService {
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
//ScheduledThreadPoolExecutor重载构造函数略.....
}
ScheduledThreadPoolExecutor 继承自ThreadPoolExecutor
,由构造函数可知它的workQueue是DelayedWorkQueue
,
在前面讲解ScheduledFutureTask
中有period
属性,关于这个属性:
- 0: 说明当前任务是
一次性
的 ,执行完毕后就退出了 。 - 负数: 说明当前任务为 fixed-delay 任务,是
固定延迟
的定时可重复执行任务 - 正数: 说明当前任务为 fixed-rate 任务 ,是
固定频率
的定时可重复执行任务
他们对应如下几种调用方式:
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
}
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit) {
}
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit) {
}
schedule(Runnable command,long delay,TimeUnit unit)
该方法的作用是提交一个延迟执行的任务,任务从提交时间算起延迟单位为 unit 的delay 时间 后开始执行 。提交的任务不是周期性任务,任务只会执行一次.
private void delayedExecute(RunnableScheduledFuture<?> task) {
//判断线程池状态是否为 RUNNING.
if (isShutdown())
reject(task);
else {
//添加任务到task
super.getQueue().add(task);
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
task.cancel(false);
else
//确保至少有一个线程在处理任务.
ensurePrestart();
}
}
scheduleAtFixedRate(Runnable command, long initialDelay,long period,TimeUnit unit)
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),
//period为负数,表示固定延迟执行...
unit.toNanos(-delay));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
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),
//period>0 ,表示固定频率执行任务;
unit.toNanos(period));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}