前言
相关系列
- 《Java & Executor & 目录》
- 《Java & Executor & ScheduledFutureTask & 源码》
- 《Java & Executor & ScheduledFutureTask & 总结》
- 《Java & Executor & ScheduledFutureTask & 问题》
涉及内容
- 《Java & Executor & Future & 总结》
- 《Java & Executor & FutureTask & 总结》
- 《Java & Executor & RunnableScheduledFuture & 总结》
- 《Java & Executor/Collection & DelayedWorkQueue & 总结》
源码
private class ScheduledFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> {
/**
* Sequence number to break ties FIFO
* 用于破坏捆绑(关联)FIFO的顺序数
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 序号
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 记录代表当前调度未来任务的唯一序号,序号会在调度未来任务创建时有全局唯一的定序器生成,被用于在两个调度未
* 来任务的执行时间相等时,决定两者的执行顺序。序号更小的调度未来任务会更先执行。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* @Description: ~
*/
private final long sequenceNumber;
/**
* The time the task is enabled to execute in nanoTime units
* 任务可用于执行的纳秒时间
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 时间
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 记录当前调度未来任务的执行时间,当当前时间大于该时间可表示当前任务可被执行,否则不可执行。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* @Description: ~
*/
private long time;
/**
* Period in nanoseconds for repeating tasks. A positive value indicates fixed-rate execution. A negative value
* indicates fixed-delay execution. A value of 0 indicates a non-repeating task.
* 重复任务的纳秒周期。正值代表固定速率执行,负值代表固定延迟执行。0值代表不是一个重复任务。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 周期
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 记录当前调度未来任务的周期性执行纳秒时间间隔,正值表示按固定速率执行;负值表示按固定延迟执行;0表示当前
* 调度未来任务不是周期性任务。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* @Description: ~
*/
private final long period;
/**
* The actual task to be re-enqueued by reExecutePeriodic
* 通过reExecutePeriodic方法进行重入队的实际任务
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* @Description: 外部任务
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* @Description: TODO
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* @Description: ~
*/
RunnableScheduledFuture<V> outerTask = this;
/**
* Index into delay queue, to support faster cancellation.
* 进入延迟队列的索引,以支持更快取消。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* @Description: 堆索引
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* @Description: 记录当前调度未来任务在延迟队列中的位置的索引
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* @Description: ~
*/
int heapIndex;
/**
* Creates a one-shot action with given nanoTime-based trigger time.
* 随着指定基础纳秒触发时间创建一个一次性的活动
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* @Description: 调度未来任务
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建指定可运行及指定可执行纳秒时间的一次性调度未来任务,并同步传入用于承载执行结果的变量。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法会先通过父类未来任务的构造方法保存可运行和承载执行结果的变量,随后保存[时间],并设置[周期]为0表示当前
* 调度未来任务为一次性任务,最后通过[定序器]获取[序号]。
*/
ScheduledFutureTask(Runnable r, V result, long ns) {
super(r, result);
this.time = ns;
this.period = 0;
this.sequenceNumber = sequencer.getAndIncrement();
}
/**
* Creates a periodic action with given nano time and period.
* 随着指定纳秒时间和周期创建一个周期活动。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 调度未来任务
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建指定可运行、指定可执行纳秒时间及指定周期的一次性/周期性调度未来任务,并同步传入用于承载执行结果的变
* 量。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法会先通过父类未来任务的构造方法保存可运行和承载执行结果的变量,随后保存[时间]、[周期],最后通过[定序器]
* 获取[序号]。
*/
ScheduledFutureTask(Runnable r, V result, long ns, long period) {
super(r, result);
this.time = ns;
this.period = period;
this.sequenceNumber = sequencer.getAndIncrement();
}
/**
* Creates a one-shot action with given nanoTime-based trigger time.
* 随着指定基础纳秒触发时间创建一次性活动
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 调度未来任务
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建指定可调用及指定可执行纳秒时间的一次性调度未来任务。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法会先通过父类未来任务的构造方法保存可调,随后保存[时间],并设置[周期]为0表示当前调度未来任务为一次性任
* 务,最后通过[定序器]获取[序号]。
*/
ScheduledFutureTask(Callable<V> callable, long ns) {
super(callable);
this.time = ns;
this.period = 0;
this.sequenceNumber = sequencer.getAndIncrement();
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 获取延迟
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 获取当前调度未来任务指定单位的剩余延迟,所谓的剩余延迟是指距离执行时间的时间间隔
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法首先会将[时间]减去当前时间的纳秒时间戳以获取延迟时间的纳秒时间戳,随后将该纳秒时间戳转换为指定单位。
*/
public long getDelay(TimeUnit unit) {
return unit.convert(time - now(), NANOSECONDS);
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 比较
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 比较当前调度未来任务与指定延迟的剩余延迟大小,小于则返回-1,等于则返回0;大于则返回1。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法首先会判断指定延迟为当前调度未来任务,是则直接返回0,因为两者的剩余延迟是相同的。如果指定延迟为
* 不为当前调度未来任务,则判断其是否为调度未来任务类型,是则将之强制转化为指定调度未来任务,并计算当前计
* 划未来任务与其的[时间]差值。如果差值小于0,则说明当前调度未来任务先于指定调度未来任务延迟到期,返回-1;
* 如果大于0,则说明指定调度未来任务先延迟到期,返回1;而如果差值为0,则需要继续判断当前调度未来任务的[序
* 号]是否小于指定调度未来任务的[序号],是则返回-1;否则返回1。因此可知,在调度未来任务一开始会使用[时间]作
* 为比较依据,而如果[时间]相同,则使用[序号]作为比较依据。
* 如果指定延迟为不为调度未来任务类型,则直接调用当前/指定调度未来任务的getDelay(TimeUnit unit)方法获取两者剩
* 余延迟时间的差值,并返回相应的-1/0/1。
*/
public int compareTo(Delayed other) {
// 方法首先会判断指定延迟为当前调度未来任务,是则直接返回0,因为两者的剩余延迟是相同的。
// compare zero if same object
// 如果是相同对象比较0
if (other == this)
return 0;
// 如果指定延迟为不为当前调度未来任务,则判断其是否为调度未来任务类型,是则将之强制转化为指定调度未来任
// 务,并计算当前调度未来任务与其的[时间]差值。如果差值小于0,则说明当前调度未来任务先于指定调度未来任务
// 延迟到期,返回-1;如果大于0,则说明指定调度未来任务先延迟到期,返回1;而如果差值为0,则需要继续判断当
// 前调度未来任务的[序号]是否小于指定调度未来任务的[序号],是则返回-1;否则返回1。因此可知,在调度未来任
// 务一开始会使用[时间]作为比较依据,而如果[时间]相同,则使用[序号]作为比较依据。
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;
}
// 如果指定延迟为不为调度未来任务类型,则直接调用当前/指定调度未来任务的getDelay(TimeUnit unit)方法获取两
// 者剩余延迟的差值,并返回相应的-1/0/1。
long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
/**
* Returns {@code true} if this is a periodic (not a one-shot) action.
* 如果当前调度未来任务是周期(不是一次性)活动则返回true。
*
* @return {@code true} if periodic 如果周期则返回true
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 是否周期
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 判断当前调度未来任务是否允许周期性执行,是则返回true;否则返回false。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法会判断[周期]是否不为0,是则说明当前调度未来任务允许周期性执行,返回true;否则说明不允许,返回false。
*/
public boolean isPeriodic() {
return period != 0;
}
/**
* Sets the next time to run for a periodic task.
* 为周期性任务设置用于执行的下个时间
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 设置下个执行时间
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 设置当前调度未来任务的下个执行时间
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法会判断[周期]是否大于0,是则说明当前调度未来任务会按固定速率执行,通过将[时间]在原有的基础上加上[周期]
* 计算得到下个执行时间并存入[时间];否则意味着当前调度未来任务需要继续延迟,通过triggerTime(long delay)方法得
* 到下个执行时间并存入[时间]。
*/
private void setNextRunTime() {
// 方法会判断[周期]是否大于0,是则说明当前调度未来任务会按固定速率执行,通过将[时间]在原有的基础上加上[周
// 期]计算得到下个执行时间并存入[时间];否则意味着当前调度未来任务需要继续延迟,通过triggerTime(long delay)
// 方法得到下个执行时间并存入[时间]。
long p = period;
if (p > 0)
time += p;
else
time = triggerTime(-p);
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 取消
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 取消当前未来任务的代表任务,取消成功则返回true;否则返回false。当代表任务结束(完成/异常/取消)时,由于已
* 处于最终状态,因此代表任务将无法被取消,方法会返回false;而如果代表任务未结束(完成/异常/取消),则当入参
* 为false时方法将阻止等待中的代表任务执行;而如果入参为true,则方法还将取消执行中的代表任务,即使代表任务可
* 能无法响应取消。而只要取消操作(阻止/取消)成功执行,无论最终的结果如何,方法都将返回true。此外,方法还会
* 根据取消移除策略决定是否将已取消的当前调度未来任务从当前调度线程池执行器的工作队列中移除。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法首先会调用的父类线程池执行器类的cancel(boolean mayInterruptIfRunning)方法取消当前调度未来任务的代理任
* 务,随后在取消操作执行成功且[取消后移除]为true且[堆索引] >= 0的情况下将当前调度未来任务从[工作队列]中移除。
* 最后返回取消的结果。
*/
public boolean cancel(boolean mayInterruptIfRunning) {
// 方法首先会调用的父类线程池执行器类的cancel(boolean mayInterruptIfRunning)方法取消当前调度未来任务的代理
// 任务,随后在取消操作执行成功且[取消后移除]为true且[堆索引] >= 0的情况下将当前调度未来任务从[工作队列]中
// 移除。最后返回取消的结果。
boolean cancelled = super.cancel(mayInterruptIfRunning);
if (cancelled && removeOnCancel && heapIndex >= 0)
remove(this);
return cancelled;
}
/**
* Overrides FutureTask version so as to reset/requeue if periodic.
* 重写未来任务版本以便周期时重置/重入队。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 运行
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 执行当前调度未来任务
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法首先会判断当前调度未来任务的代表任务是否周期性执行,随后将判断的结果作为参数带入
* canRunInCurrentRunState(boolean periodic)方法判断代理任务能否在当前运行状态中执行。如果不可执行,则将该
* 代表任务取消,目的是阻止该代表人物被后续执行;而如果可以执行,并且当前代表任务不是周期性任务的话,调用的
* 父类未来任务的run()方法执行任务;而如果当前代表任务是周期性任务,则需要调用未来任务的runAndRest()方法执行
* 任务,该方法与run()方法的差别在于不会保存代表任务的执行结果,因此除非被取消,否则可以不断的执行。
* 周期性任务被执行后,为了保证下一次执行,需要调用setNextRunTime()方法为代表任务设置新的执行时间,再通过
* reExecutePeriodic(RunnableScheduledFuture<?> task)方法将当前调度未来任务重新加入当前调度线程池执行器的[工
* 作队列]中。
*/
public void run() {
// 方法首先会判断当前调度未来任务的代表任务是否周期性执行,随后将判断的结果作为参数带入
// canRunInCurrentRunState(boolean periodic)方法判断代理任务能否在当前运行状态中执行。如果不可执行,则将该
// 代表任务取消,目的是阻止该代表人物被后续执行;而如果可以执行,并且当前代表任务不是周期性任务的话,调
// 用的父类未来任务的run()方法执行任务;而如果当前代表任务是周期性任务,则需要调用未来任务的runAndRest()方
// 法执行任务,该方法与run()方法的差别在于不会保存代表任务的执行结果,因此除非被取消,否则可以不断的执行。
// 周期性任务被执行后,为了保证下一次执行,需要调用setNextRunTime()方法为代表任务设置新的执行时间,再通过
// reExecutePeriodic(RunnableScheduledFuture<?> task)方法将当前调度未来任务重新加入当前调度线程池执行器的[工
// 作队列]中。
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) {
setNextRunTime();
reExecutePeriodic(outerTask);
}
}
}