Java Executor ScheduledThreadPoolExecutor 源码
前言
相关系列
- 《Java & Executor & 目录》
- 《Java & Executor & ScheduledThreadPoolExecutor & 源码》
- 《Java & Executor & ScheduledThreadPoolExecutor & 总结》
- 《Java & Executor & ScheduledThreadPoolExecutor & 问题》
涉及内容
- 《Java & Executor & 总结》
- 《Java & Executor & ExecutorService & 源码》
- 《Java & Executor & ScheduledExecutorService & 总结》
- 《Java & Executor & ThreadPoolExecutor & 总结》
- 《Java & Executor & Future & 总结》
- 《Java & Executor & FutureTask & 总结》
- 《Java & Executor & ScheduledFutureTask & 总结》
- 《Java & Collection/Executor & BlockingQueue & 总结》
- 《Java & Collection/Executor & DelayedWorkQueue & 总结》
- 《Java & Executor & Callable & 总结》
- 《Java & Thread & Runnable & 总结》
源码
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
package juc;
import juc.locks.Condition;
import juc.locks.ReentrantLock;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import static juc.TimeUnit.NANOSECONDS;
/**
* A {@link ThreadPoolExecutor} that can additionally schedule commands to run after a given delay, or to execute
* periodically. This class is preferable to {@link Timer} when multiple worker threads are needed, or when the additional
* flexibility or capabilities of {@link ThreadPoolExecutor} (which this class extends) are required.
* 一个可以在指定延迟之后额外调度命令执行,或者周期性执行的线程池执行器。当需要多工作者线程,或者当线程池执行器(
* 调度线程池执行器继承了线程池执行器)需要额外的弹性或能力时它比Timer更好。
* <p>
* Delayed tasks execute no sooner than they are enabled, but without any real-time guarantees about when, after they are
* enabled, they will commence. Tasks scheduled for exactly the same execution time are enabled in first-in-first-out (FIFO)
* order of submission.
* 延迟任务不会一可用就立刻执行,但是无法保证当它们可用时/后会开始实时执行。为恰好完全相同的执行时间安排的任务以
* 先进先出(FIFO)的提交顺序启用。
* <p>
* When a submitted task is cancelled before it is run, execution is suppressed. By default, such a cancelled task is not
* automatically removed from the work queue until its delay elapses. While this enables further inspection and monitoring,
* it may also cause unbounded retention of cancelled tasks. To avoid this, set {@link #setRemoveOnCancelPolicy} to
* {@code true}, which causes tasks to be immediately removed from the work queue at time of cancellation.
* 当一个递交的任务在运行之前被取消,执行将被阻止。默认情况下,如此一个已取消的任务并不会自动地从工作队列中移除
* 直至它的延迟到期。尽管这能够进一步检查和监视但它也可能导致取消任务无限制的保留。未必避免这一点,设置
* setRemoveOnCancelPolicy(boolean value)方法的参数为true,能导致任务在取消的时间立即从工作队列中移除。
* <p>
* Successive executions of a task scheduled via {@code scheduleAtFixedRate} or {@code scheduleWithFixedDelay} do not
* overlap. While different executions may be performed by different threads, the effects of prior executions
* <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> those of subsequent ones.
* 一个任务通过scheduleAtFixedRate或scheduleWithFixedDelay方法连续的执行不会重叠。尽管不同的执行可能通过不同的线
* 程执行,优先执行的影响先行发生于随后其中随后发生的。
* <p>
* While this class inherits from {@link ThreadPoolExecutor}, a few of the inherited tuning methods are not useful for it. In
* particular, because it acts as a fixed-sized pool using {@code corePoolSize} threads and an unbounded queue, adjustments
* to {@code maximumPoolSize} have no useful effect. Additionally, it is almost never a good idea to set {@code corePoolSize}
* to zero or use {@code allowCoreThreadTimeOut} because this may leave the pool without threads to handle tasks once they
* become eligible to run.
* 尽管类继承自线程池执行器,但一些继承的调优方法对它并没有用处。尤其是因为它使用[核心池大小]数量的线程和无界队列充
* 当一个固定大小的吃,调节[最大池大小]并没有用处。此外,设置[核心池大小]为0或使用[允许核心线程]几乎从来就不是一个好
* 注意,因为这可能使得池没有线程在任务变的适合执行时处理任务。
* <p>
* <b>Extension notes:</b> This class overrides the {@link ThreadPoolExecutor#execute(Runnable) execute} and
* {@link AbstractExecutorService#submit(Runnable) submit} methods to generate internal {@link ScheduledFuture} objects to
* control per-task delays and scheduling. To preserve functionality, any further overrides of these methods in subclasses must
* invoke superclass versions, which effectively disables additional task customization. However, this class provides alternative
* protected extension method {@code decorateTask} (one version each for {@code Runnable} and {@code Callable}) that can be
* used to customize the concrete task types used to execute commands entered via {@code execute}, {@code submit},
* {@code schedule}, {@code scheduleAtFixedRate}, and {@code scheduleWithFixedDelay}. By default, a
* {@code ScheduledThreadPoolExecutor} uses a task type extending {@link FutureTask}. However, this may be modified or replaced
* using subclasses of the form:
* 衍生简介:该类重写了线程池执行器的execute(Runnable)方法和抽象执行器服务的submit(Runnable) 方法以生成内部调度未来对象以
* 控制每个任务延迟和假话。为了功能性防止这些方法在子类中进一步的重写必须调用父类版本,这有效的禁用了额外的任务定制。此
* 外,该类提供可供备选的受保护衍生方法decorateTask()可用于定制具体任务类型用于执行通过execute/submit/schedule/
* scheduleAtFixedRate/scheduleWithFixedDelay方法进入的命令。默认情况下,一个调度线程池执行器使用继承自未来任务的任务类型。
* 此外,这可能使用该格式的子类进行修改或替换:
* <pre> {@code
* public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
*
* static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
*
* protected <V> RunnableScheduledFuture<V> decorateTask(Runnable r, RunnableScheduledFuture<V> task) {
* return new CustomTask<V>(r, task);
* }
*
* protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> c, RunnableScheduledFuture<V> task) {
* return new CustomTask<V>(c, task);
* }
* // ... add constructors, etc.
* }}</pre>
*
* @author Doug Lea
* @since 1.5
*/
public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService {
/*
* This class specializes ThreadPoolExecutor implementation by
* 该类通过以下性质特化线程池执行器实现
* 1. Using a custom task type, ScheduledFutureTask for tasks, even those that don't require scheduling (i.e., those
* submitted using ExecutorService execute, not ScheduledExecutorService methods) which are treated as delayed tasks
* with a delay of zero.
* 1. 使用定制任务类型为任务的调度未来任务,即使任务不需要调度执行(通过执行器方法递交而不是执行器接口方法)也
* 会被看做一个延迟为0的延迟任务。
* 2. Using a custom queue (DelayedWorkQueue), a variant of unbounded DelayQueue. The lack of capacity constraint and
* the fact that corePoolSize and maximumPoolSize are effectively identical simplifies some execution mechanics (see
* delayedExecute) compared to ThreadPoolExecutor.
* 2. 使用定制的队列(延迟工作队列),一个无界延迟队列的变种。相较于线程池执行器,其容量限制的缺乏以及核心池大
* 小与最大池大小实际上相等能简化某些执行机制(看delayedExecute)。
* 3. Supporting optional run-after-shutdown parameters, which leads to overrides of shutdown methods to remove and
* cancel tasks that should NOT be run after shutdown, as well as different recheck logic when task (re)submission
* overlaps with a shutdown.
* 3. 支持可选关闭后运行参数,这会导致关闭方法的重写移除和取消不应该在关闭后运行的任务,以及当任务随着关闭(重)
* 递交时不同的检查逻辑。
* 4. Task decoration methods to allow interception and instrumentation, which are needed because subclasses cannot
* otherwise override submit methods to get this effect. These don't have any impact on pool control logic though.
* 4. 任务装饰方法允许拦截及仪表化,这是有需要的因为子类无法以其它方式重写递交方法以获得该效果。虽然这不会对池
* 控制逻辑产生任何影响(即任务装饰方法允许拦截和仪表化只用便于获取效果...啥效果?但是对池控制逻辑没有任何影响)。
*/
/**
* False if should cancel/suppress periodic tasks on shutdown.
* 如果应该在关闭后取消/阻止周期任务则为false。
*
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* @Description: 关闭后继续存在周期任务集
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* @Description: 记录当前调度线程池执行器关闭后是否保留周期任务,是则为true;否则为false
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* @Description: ~
*/
private volatile boolean continueExistingPeriodicTasksAfterShutdown;
/**
* False if should cancel non-periodic tasks on shutdown.
* 如果应该在周期后取消非周期任务则为false。
*
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* @Description: 关闭后执行存在延迟任务集
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* @Description: 记录当前调度线程池执行器关闭后是否继续延迟任务,是则为true;否则为false
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* @Description: ~
*/
private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
/**
* True if ScheduledFutureTask.cancel should remove from queue
* 如果调度未来任务取消后应该从队列中移除则为true
*
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* @Description: 取消时移除
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* @Description: 记录当前调度线程池执行器的调度未来任务取消后是否应该从队列中移除,是则返回true;否则返回false。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* @Description: ~
*/
private volatile boolean removeOnCancel = false;
/**
* Sequence number to break scheduling ties, and in turn to guarantee FIFO order among tied entries.
* 顺序数以损坏调度关系,并转而保证关联项的FIFO的顺序
*
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* @Description: 定序器
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* @Description: 持有调度线程池执行器类全局唯一的一个原子大整数对象,用于为每个调度未来任务生成唯一序号。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* @Description: ~
*/
private static final AtomicLong sequencer = new AtomicLong();
/**
* Returns current nanosecond time.
* 返回当前纳秒时间
*
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* @Description: 现在
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* @Description: 获取当前纳秒时间
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* 方法通过System.nanoTime()方法直接获取当前时间的纳秒时间戳,但这个时间戳的起点并不是1970年,一般是无法确定的,
* 但通常是系统启动的时间。
*/
final long now() {
// 方法通过System.nanoTime()方法直接获取当前时间的纳秒时间戳,但这个时间戳的起点并不是1970年,一般是无法确
// 定的,但通常是系统启动的时间。
return System.nanoTime();
}
// ----------------------------
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);
}
}
}
// ----------------------------
/**
* Returns true if can run a task given current run state and run-after-shutdown parameters.
* 如果可以执行指定当前运行状态及关闭后运行参数的任务则返回true。
*
* @param periodic true if this task periodic, false if delayed 如果任务是周期性的则返回true;如果延迟则返回false。
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 能否在当前运行状态中运行
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 判断当前调度未来任务的代表任务是否可以在当前调度线程池执行器的运行状态中执行,是则返回true;否则返回false。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法首先会根据指定周期性选择isRunningOrShutdown(boolean shutdownOK)方法的传参,如果指定周期性为true则选择
* [关闭后继续存在周期任务集]作为传参;否则选择[关闭后执行存在延迟任务集]作为传参,随后返回方法的执行结果。如
* 果当前调度线程池执行器正处于RUNNING(运行中)状态,则无论入参为何当前调度未来任务都运行执行;而如果当前
* 调度线程池执行器已被关闭,则当前调度未来任务的代表任务能否执行则由入参决定。默认情况下如果当前调度未来任
* 务的代表任务是周期性任务则不允许执行,而如果是延迟任务则运行执行。因为周期性执行可以理解为任务被重复用的
* 递交,而调度线程池执行器因为继承自线程池执行器是不允许在关闭后递交任务的。而延迟任务本质则属于递交后尚未
* 执行的任务。在线程池执行器的定义中,即使被关闭,但已递交的任务是允许被继续执行的。
*/
boolean canRunInCurrentRunState(boolean periodic) {
// 方法首先会根据指定周期性选择isRunningOrShutdown(boolean shutdownOK)方法的传参,如果指定周期性为true则
// 选择[关闭后继续存在周期任务集]作为传参;否则选择[关闭后执行存在延迟任务集]作为传参,随后返回方法的执行
// 结果。如果当前调度线程池执行器正处于RUNNING(运行中)状态,则无论入参为何当前调度未来任务都运行执行;
// 而如果当前调度线程池执行器已被关闭,则当前调度未来任务的代表任务能否执行则由入参决定。默认情况下如果
// 当前调度未来任务的代表任务是周期性任务则不允许执行,而如果是延迟任务则运行执行。因为周期性执行可以理
// 解为任务被重复用的递交,而调度线程池执行器因为继承自线程池执行器是不允许在关闭后递交任务的。而延迟任
// 务本质则属于递交后尚未执行的任务。在线程池执行器的定义中,即使被关闭,但已递交的任务是允许被继续执行
// 的。
return isRunningOrShutdown(periodic ? continueExistingPeriodicTasksAfterShutdown : executeExistingDelayedTasksAfterShutdown);
}
/**
* Main execution method for delayed or periodic tasks. If pool is shut down, rejects the task. Otherwise adds task
* to queue and starts a thread, if necessary, to run it. (We cannot prestart the thread to run the task because the
* task (probably) shouldn't be run yet.) If the pool is shut down while the task is being added, cancel and remove it if
* required by state and run-after-shutdown parameters.
* 延迟/周期任务的主执行方法。如果池被关闭,拒绝任务。否则新增任务至队列并且如果必要开启一个线程来执行他。
* (我们不可以预启动线程来执行任务因为任务(可能)还不应该执行。)如果池在任务新增期间关闭,如果状态和关闭
* 后参数需要则取消并移除它。
*
* @param task the task 用于入队的任务
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 延迟执行
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 将指定可运行调度任务重新加入当前调度线程池执行器的工作队列中并触发执行
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法首先会判断当前调度线程池执行器是否关闭,是则直接拒绝执行指定可运行调度未来。这里可能会有所疑惑,因为
* 如果当前调度线程池执行器是SHUTDOWN(关闭)状态且设置允许的话,延迟任务是允许在SHUTDOWN(关闭)状态下
* 执行的,但实际是该方法中传入的指定可运行调度未来都是由外部传递的,属于阻止执行的范围,因此可以直接拒绝执
* 行。
* 如果没有关闭,则将指定可运行调度未来加入当前调度线程池执行器的[工作队列]中,并再次判断是否关闭以避免由于
* 并发导致的在加入过程中当前调度线程池执行器关闭的情况。此时由于指定可运行调度未来已加入[工作队列],并且也
* 无法确定当前调度线程池执行器究竟时在加入之前还是之后被关闭的,因此统一视作加入之后被关闭的逻辑处理。此时
* 如果设置允许指定可运行调度未来继续执行则将之保留并预启动一个线程来执行任务。之所以要与启动一个线程是为了
* 避免当前调度线程池执行器一个线程都没有的情况;否则将之移除并取消。取消目的是阻止任务被执行。
*/
private void delayedExecute(RunnableScheduledFuture<?> task) {
// 方法首先会判断当前调度线程池执行器是否关闭,是则直接拒绝执行指定可运行调度未来。这里可能会有所疑惑,
// 因为如果当前调度线程池执行器是SHUTDOWN(关闭)状态且设置允许的话,延迟任务是允许在SHUTDOWN(关闭)
// 状态下执行的,但实际是该方法中传入的指定可运行调度未来都是由外部传递的,属于阻止执行的范围,因此可以
// 直接拒绝执行。
if (isShutdown())
reject(task);
else {
// 如果没有关闭,则将指定可运行调度未来加入当前调度线程池执行器的[工作队列]中,并再次判断是否关闭以避
// 免由于并发导致的在加入过程中当前调度线程池执行器关闭的情况。此时由于指定可运行调度未来已加入[工作
// 队列],并且也无法确定当前调度线程池执行器究竟时在加入之前还是之后被关闭的,因此统一视作加入之后被
// 关闭的逻辑处理。此时如果设置允许指定可运行调度未来继续执行则将之保留并预启动一个线程来执行任务。之
// 所以要与启动一个线程是为了避免当前调度线程池执行器一个线程都没有的情况;否则将之移除并取消。取消目
// 的是阻止任务被执行。
super.getQueue().add(task);
if (isShutdown() && !canRunInCurrentRunState(task.isPeriodic()) && remove(task))
task.cancel(false);
else
ensurePrestart();
}
}
/**
* Requeues a periodic task unless current run state precludes it. Same idea as delayedExecute except drops task
* rather than rejecting.
* 重入队一个周期性任务,除非当前运行状态阻止他。理念与delayedExecute(RunnableScheduledFuture<?> task)方法相
* 同除了删除而不是拒绝任务。
*
* @param task the task 用于入队的任务
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 重执行周期
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 将指定可运行调度任务重新加入当前调度线程池执行器的工作队列中并触发执行
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法首先会判断当前调度线程池执行器的运行状态是否可以执行周期性任务,否则什么也不做,以为这直接抛弃指定运
* 行调度任务;否则将指定运行调度未来加入[工作队列]中。由于使用的是插入方法的异常形式实现,因此如果当[工作队
* 列]无容量容纳指定运行调度未来时会抛出非法状态异常。
* 指定运行调度未来成功加入[工作队列],会再次判断当前调度线程池执行器的运行状态是否可以执行周期性任务,这是
* 为了避免当前调度线程池执行器运行状态发生改变导致无法执行任务的情况。如果可以不可以执行,则需要将已入队的
* 指定可运行调度未来从[工作队列]中移除,并随后将之取消;否则就要预启动一个核心线程来执任务,因为此时当前调
* 度线程池执行器中的线程可能因为无任务可执行而销毁了所有线程。
*/
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
// 方法首先会判断当前调度线程池执行器的运行状态是否可以执行周期性任务,否则什么也不做,以为这直接抛弃指
// 定运行调度任务;否则将指定运行调度未来加入[工作队列]中。由于使用的是插入方法的异常形式实现,因此如果
// 当[工作队列]无容量容纳指定运行调度未来时会抛出非法状态异常。
if (canRunInCurrentRunState(true)) {
super.getQueue().add(task);
// 指定运行调度未来成功加入[工作队列],会再次判断当前调度线程池执行器的运行状态是否可以执行周期性任务,
// 这是为了避免当前调度线程池执行器运行状态发生改变导致无法执行任务的情况。如果可以不可以执行,则需要
// 将已入队的指定可运行调度未来从[工作队列]中移除,并随后将之取消;否则就要预启动一个核心线程来执任务,
// 因为此时当前调度线程池执行器中的线程可能因为无任务可执行而销毁了所有线程。
if (!canRunInCurrentRunState(true) && remove(task))
task.cancel(false);
else
ensurePrestart();
}
}
/**
* Cancels and clears the queue of all tasks that should not be run due to shutdown policy. Invoked within
* super.shutdown.
* 取消并清理所有由于关闭策略而不应该执行的任务的队列。在super.shutdown中调用。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 重执行周期
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 将指定可运行调度任务重新加入当前调度线程池执行器的工作队列中并触发执行
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法首先会获取[工作队列]/[关闭后执行存在延迟任务集]/[关闭后继续存在周期任务集],如果[关闭后执行存在的延迟任
* 务]及[关闭后继续存在周期任务集]都不允许任务在当前调度线程池执行器中执行,则通过快照的方式遍历[工作队列]以取
* 消所有的任务,随后清理整个[工作队列]。
* 而如果[关闭后执行存在延迟任务集]或[关闭后继续存在周期任务集]中的任意一个支持任务在当前调度线程池执行器关闭
* 后执行,则通过快照的方式遍历[工作队列]以取消其中的目标任务,具体看任务是否是周期任务且配置是否支持执行或
* 者任务是否已被取消,是则将任务从[工作队列]中移除并将之取消(就可能有重复取消,但重复取消没有什么影响)。
* 从无法执行的任务从[工作队列]中全部后,最后调用尝试终结任务。
* @Description: ----------------------------------------------------------- 疑问 -----------------------------------------------------------
* TODO 为什么使用快照遍历而不是迭代器遍历?
*/
@Override
void onShutdown() {
// 方法首先会获取[工作队列]/[关闭后执行存在延迟任务集]/[关闭后继续存在周期任务集],如果[关闭后执行存在的延
// 迟任务]及[关闭后继续存在周期任务集]都不允许任务在当前调度线程池执行器中执行,则通过快照的方式遍历[工作
// 队列]以取消所有的任务,随后清理整个[工作队列]。
BlockingQueue<Runnable> q = super.getQueue();
boolean keepDelayed = getExecuteExistingDelayedTasksAfterShutdownPolicy();
boolean keepPeriodic = getContinueExistingPeriodicTasksAfterShutdownPolicy();
if (!keepDelayed && !keepPeriodic) {
for (Object e : q.toArray())
if (e instanceof RunnableScheduledFuture<?>)
((RunnableScheduledFuture<?>) e).cancel(false);
q.clear();
} else {
// Traverse snapshot to avoid iterator exceptions
// 遍历快照以避免迭代器异常
// 而如果[关闭后执行存在延迟任务集]或[关闭后继续存在周期任务集]中的任意一个支持任务在当前调度线程池执行
// 器关闭后执行,则通过快照的方式遍历[工作队列]以取消其中的目标任务,具体看任务是否是周期任务且配置是
// 否支持执行或者任务是否已被取消,是则将任务从[工作队列]中移除并将之取消(就可能有重复取消,但重复取
// 消没有什么影响)。
for (Object e : q.toArray()) {
if (e instanceof RunnableScheduledFuture) {
RunnableScheduledFuture<?> t = (RunnableScheduledFuture<?>) e;
if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) || t.isCancelled()) {
// also remove if already cancelled
if (q.remove(t))
t.cancel(false);
}
}
}
}
// 从无法执行的任务从[工作队列]中全部后,最后调用尝试终结任务。
tryTerminate();
}
/**
* Modifies or replaces the task used to execute a runnable. This method can be used to override the concrete class
* used for managing internal tasks. The default implementation simply returns the given task.
* 修改或替换任务用于执行运行。该方法可用于为管理内部任务覆盖具体的类。其默认实现简单返回执行任务。
*
* @param runnable the submitted Runnable 递交可运行
* @param task the task created to execute the runnable 创建的任务用于执行可运行
* @param <V> the type of the task's result 任务结果的类型
* @return a task that can execute the runnable 可知执行可运行的任务
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 装饰任务
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 未知
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法直接通过返回指定任务实现
* @since 1.6
*/
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
return task;
}
/**
* Modifies or replaces the task used to execute a callable. This method can be used to override the concrete class
* used for managing internal tasks. The default implementation simply returns the given task.
* 修改或替换任务用于执行可调用。该方法可用于为管理内部任务覆盖具体的类。其默认实现简单返回执行任务。
*
* @param callable the submitted Callable 递交的可调用
* @param task the task created to execute the callable 已创建的任务用于执行可调用
* @param <V> the type of the task's result 任务的结果类型
* @return a task that can execute the callable 一个可以执行可调用的任务
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 装饰任务
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 未知
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法直接通过返回指定任务实现
* @since 1.6
*/
protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task) {
return task;
}
/**
* Creates a new {@code ScheduledThreadPoolExecutor} with the given core pool size.
* 通过指定核心池大小创建一个调度线程池执行器
*
* @param corePoolSize the number of threads to keep in the pool, even if they are idle, unless
* {@code allowCoreThreadTimeOut} is set
* 在池中保持的线程数量,即使它们限制,除非允许核心线程超时被设置
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* 非法参数异常:如果核心池大小 < 0
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* ~
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建指定核心池大小的调度线程池执行器
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法直接调用父类线程池执行器的构造方法实现,除[核心池大小]会采用指定核心池大小外,该构造方法会默认将[最大
* 池大小]设置为Integer.MAX_VALUE,但实际最多只能创建2 ^ 29 - 1个线程;[持续存活时间]设置为0,表示当无任务可
* 获取执行时非核心线程会立即销毁;[时间单位]设置为纳秒;[工作队列]设置为自定义的延迟工作队列,[线程工厂]设置
* 为默认线程工厂;[拒绝执行处理器]设置为中断策略。
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {
// 方法直接调用父类线程池执行器的构造方法实现,除[核心池大小]会采用指定核心池大小外,该构造方法会默认将
// [最大池大小]设置为Integer.MAX_VALUE,但实际最多只能创建2 ^ 29 - 1个线程;[持续存活时间]设置为0,表示当
// 无任务可获取执行时非核心线程会立即销毁;[时间单位]设置为纳秒;[工作队列]设置为自定义的延迟工作队列,[
// 线程工厂]设置为默认线程工厂;[拒绝执行处理器]设置为中断策略。
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}
/**
* Creates a new {@code ScheduledThreadPoolExecutor} with the given initial parameters.
* 通过指定初始参数创建一个新调度线程池执行器
*
* @param corePoolSize the number of threads to keep in the pool, even if they are idle, unless
* {@code allowCoreThreadTimeOut} is set
* 在池中维持的线程数量,即使他们是闲置的,除非允许核心线程超时被设置
* @param threadFactory the factory to use when the executor creates a new thread
* 当执行器创建新线程时使用的工厂
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* 非法参数异常:如果核心池大小小于0
* @throws NullPointerException if {@code threadFactory} is null
* 空指针异常:如果线程工厂为null
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* ~
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建指定核心池大小及线程工厂的调度线程池执行器
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法直接调用父类线程池执行器的构造方法实现,除[核心池大小]/[线程工厂]会采用指定参数外,该构造方法会默认将
* [最大池大小]设置为Integer.MAX_VALUE,但实际最多只能创建2 ^ 29 - 1个线程;[持续存活时间]设置为0,表示当无任
* 务可获取执行时非核心线程会立即销毁;[时间单位]设置为纳秒;[拒绝执行处理器]设置为中断策略。
*/
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
// 方法直接调用父类线程池执行器的构造方法实现,除[核心池大小]/[线程工厂]会采用指定参数外,该构造方法会默
// 认将[最大池大小]设置为Integer.MAX_VALUE,但实际最多只能创建2 ^ 29 - 1个线程;[持续存活时间]设置为0,表
// 示当无任务可获取执行时非核心线程会立即销毁;[时间单位]设置为纳秒;[拒绝执行处理器]设置为中断策略。
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory);
}
/**
* Creates a new ScheduledThreadPoolExecutor with the given initial parameters.
* 随着指定初始参数创建一个调度线程执行器
*
* @param corePoolSize the number of threads to keep in the pool, even if they are idle, unless
* {@code allowCoreThreadTimeOut} is set
* 在池中维持的线程数量,即使它们是闲置的,除非允许核心线程超时被设置
* @param handler the handler to use when execution is blocked because the thread bounds and queue capacities
* are reached
* 当执行后因为线程限制以及队列容量已到达而阻塞时使用的处理器
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* 非法参数异常:如果核心池大小小于0
* @throws NullPointerException if {@code handler} is null
* 空指针异常:如果处理器为null
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* ~
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建指定核心池大小及拒绝执行处理器的调度线程池执行器
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法直接调用父类线程池执行器的构造方法实现,除[核心池大小]/[拒绝执行处理器]会采用指定参数外,该构造方法会
* 默认将[最大池大小]设置为Integer.MAX_VALUE,但实际最多只能创建2 ^ 29 - 1个线程;[持续存活时间]设置为0,表示
* 当无任务可获取执行时非核心线程会立即销毁;[时间单位]设置为纳秒;[工作队列]设置为自定义的延迟工作队列,[线
* 程工厂]设置为默认线程工厂。
*/
public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {
// 方法直接调用父类线程池执行器的构造方法实现,除[核心池大小]/[拒绝执行处理器]会采用指定参数外,该构造方
// 法会默认将[最大池大小]设置为Integer.MAX_VALUE,但实际最多只能创建2 ^ 29 - 1个线程;[持续存活时间]设置
// 为0,表示当无任务可获取执行时非核心线程会立即销毁;[时间单位]设置为纳秒;[工作队列]设置为自定义的延迟
// 工作队列,[线程工厂]设置为默认线程工厂。
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), handler);
}
/**
* Creates a new ScheduledThreadPoolExecutor with the given initial parameters.
* 随着指定初始参数创建一个调度线程执行器。
*
* @param corePoolSize the number of threads to keep in the pool, even if they are idle, unless
* {@code allowCoreThreadTimeOut} is set
* 在池中维持的线程数量,即使它们是闲置的,除非允许核心线程超时被设置
* @param threadFactory the factory to use when the executor creates a new thread
* 当执行器创建新线程时使用的工厂
* @param handler the handler to use when execution is blocked because the thread bounds and queue capacities
* are reached
* 当执行后因为线程限制以及队列容量已到达而阻塞时使用的处理器
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* 非法参数异常:如果核心池大小小于0
* @throws NullPointerException if {@code threadFactory} or
* {@code handler} is null
* 空指针异常:如果线程工厂或处理器为null
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* ~
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建指定核心池大小、线程工厂及拒绝执行处理器的调度线程池执行器
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法直接调用父类线程池执行器的构造方法实现,除[核心池大小]、[线程工厂]及[拒绝执行处理器]会采用指定参数外,
* 该构造方法会默认将[最大池大小]设置为Integer.MAX_VALUE,但实际最多只能创建2 ^ 29 - 1个线程;[持续存活时间]
* 设置为0,表示当无任务可获取执行时非核心线程会立即销毁;[时间单位]设置为纳秒;[工作队列]设置为自定义的延
* 迟工作队列。
*/
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
//方法直接调用父类线程池执行器的构造方法实现,除[核心池大小]、[线程工厂]及[拒绝执行处理器]会采用指定参数
// 外,该构造方法会默认将[最大池大小]设置为Integer.MAX_VALUE,但实际最多只能创建2 ^ 29 - 1个线程;[持续存
// 活时间]设置为0,表示当无任务可获取执行时非核心线程会立即销毁;[时间单位]设置为纳秒;[工作队列]设置为自
// 定义的延迟工作队列。
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory, handler);
}
/**
* Returns the trigger time of a delayed action.
* 返回延迟活动的触发时间
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 触发时间
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 计算以当前时间为基础时间经过指定延迟后的触发时间
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先会将指定延迟通过指定时间单位转换为纳秒时间戳,并将该时间戳作为参数调用triggerTime(long delay)方
* 法获取触发时间。但在将指定延迟转换为时间戳之前,会判断指定延迟是否小于0,是则直接将0做为参数,因为延迟小
* 于0意味着延迟已经到期,其相应的活动可以直接执行,传入负数可能反而会令计算得到的触发时间小于当前时间,从而
* 错过执行。
*/
private long triggerTime(long delay, TimeUnit unit) {
// ---- 方法首先会将指定延迟通过指定时间单位转换为纳秒时间戳,并将该时间戳作为参数调用triggerTime(long delay)
// 方法获取触发时间。但在将指定延迟转换为时间戳之前,会判断指定延迟是否小于0,是则直接将0做为参数,因为延
// 迟小于0意味着延迟已经到期,其相应的活动可以直接执行,传入负数可能反而会令计算得到的触发时间小于当前时
// 间,从而错过执行。
return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
}
/**
* Returns the trigger time of a delayed action.
* 返回延迟活动的触发时间
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 触发时间
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 计算以当前时间为基础时间经过指定延迟后的触发时间
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先会判断指定延迟是否小于Long.MAX_VALUE >> 1,是则直接将指定延迟与now()方法返回的当前时间相加以
* 计算触发时间。之所以执行该判断是因为计算得到的触发时间可能超过Long.MAX_VALUE而成为负数,因此需要对该情
* 况进行特殊处理。
* ---- 当指定延迟小于Long.MAX_VALUE >> 1时,基本可以100%确定计算得到的触发时间不能超过Long类型的最大值,原
* 因是因为即使我们将指定延迟设置为Long.MAX_VALUE >> 1,即4611686018427387903,也要等到
* 146140482-04-24 23:36:27才可能导致溢出。因此至少一亿四千五百万年内我们不需要去考虑在指定延迟小于
* Long.MAX_VALUE >> 1时计算得到的触发时间超出Long.MAX_VALUE的情况。而且请注意:上述这个日期我们是基于
* 1970-01-01 08:00:00(北京时间)计算得到的。而now()方法的底层方法System.nanoTime()返回的纳秒时间则通常是基
* 于系统启动时间(即通常意义上的开机时间)得到的,因此实际溢出的时间只会比146140482-04-24 23:36:27更久,
* 所以虽然在理论上严格的说是无法100%保证不溢出的,但是完全可以视作100%保证不溢出。
* ---- 而在指定延迟大于等于Long.MAX_VALUE >> 1的情况下,计算得到的触发时间超过Long.MAX_VALUE的概率就大大提
* 升了,因此此时需要进行相关的特殊处理。请注意!这里进行的特殊处理并不是避免计算得到的触发时间超过
* Long.MAX_VALUE,而是使触发时间与[工作队列]中头延迟的剩余延迟的差值不超过Long.MAX_VALUE,关于该操作的意
* 义会在下文详述,但在此处则需要明确的是:基于指定延迟和当前时间计算得到的触发时间是可能超过
* Long.MAX_VALUE的。
*/
long triggerTime(long delay) {
return now() + ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
/**
* Constrains the values of all delays in the queue to be within Long.MAX_VALUE of each other, to avoid overflow in
* compareTo. This may occur if a task is eligible to be dequeued, but has not yet been, while some other task is added
* with a delay of Long.MAX_VALUE.
* 将队列中所有延迟的每个值都限制在Long.MAX_VALUE之内,以避免在比较中溢出(超出Long.MAX_VALUE会呈现负数,则
* 在比较时相间就会变成相加而导致结果溢出)。如果一个任务有资格退出队列,但还没有退出队列,而其他一些任务以
* Long.MAX_VALUE的延迟添加,则可能发生这种情况。
*
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 溢出释放
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 计算当前锁允许的最大
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法首先会从当前调度线程池执行器的[工作队列]中获取头延迟,如果头延迟不为null,则获取头延迟的剩余延迟。随
* 后如果发现头延迟剩余延迟小于0且指定延迟减去头延迟剩余延迟的结果小于0,则将指定延迟赋值为Long.MAX_VALUE +
* 头延迟剩余延迟。
* ---- 头延迟剩余延迟小于0意味着头延迟已延迟到期,只是因为各方面的原因(包含但不限于系统调度、线程创建/唤醒等
* 方面的延迟)没有被调度线程池执行器及时的执行。而指定延迟减去头延迟剩余延迟的结果小于0则意味着结果超出了
* Long.MAX_VALUE。超出的原因是因为头延迟的剩余延迟本身就为负数,因此指定延迟 - 头延迟剩余延迟时间的本质是加
* 法操作。在这种情况下如果指定延迟本身就很接近甚至等于Long.MAX_VALUE,就会导致两者相减的结果超过
* Long.MAX_VALUE。
* ---- 在结果超过Long.MAX_VALUE的情况下,方法会将指定延迟赋值为Long.MAX_VALUE + 头延迟剩余延迟,由于头延迟剩
* 余延迟为负数,因此该操作本质为减法操作。该操作的目的是避免当基于该指定延迟计算得到的触发时间所属的调度未来
* 任务与[工作队列]中的延迟(本质也是调度未来任务)进行剩余延迟比对时(所属调度未来任务加入[工作队列]时发生),
* 两者的差值不会出现超过Long.MAX_VALUE的情况。由于头延迟的剩余延迟是实际最小的,因此只要与之相减得到的结果不
* 会超过Long.MAX_VALUE,则与[工作队列]中的任意延迟进行比对就都不会导致超出的情况发生。
* ---- 已知在指定延时时间与头延迟剩余延迟相减的结果超过Long.MAX_VALUE的情况下,计算得到的触发时间为(已知的是
* 当前时间(2)会在当前时间(1)后获取,因此当前时间(2) >= 当前时间(1)):
* 触发时间 = 当前时间(1) + Long.MAX_VALUE + 头延迟剩余延迟(负数)
* = 当前时间(1) + Long.MAX_VALUE + (头延迟触发时间 - 当前时间(2))
* = 当前时间(1) + Long.MAX_VALUE + 头延迟触发时间 - 当前时间(2)
* <= Long.MAX_VALUE + 头延迟触发时间
* 而当触发时间所属调度未来任务入队与任意延迟进行剩余延迟比对时(这里直接拿头延迟进行比对),比对差值的计算如
* 下:
* 差值 <= (新调度未来任务触发时间 - 当前时间(3)) - (头延迟触发时间 - 当前时间(3))
* <= Long.MAX_VALUE + 头延迟触发时间 - 当前时间(3) - 头延迟触发时间 + 当前时间(3)
* <= Long.MAX_VALUE + 头延迟触发时间 - 头延迟触发时间
* <= Long.MAX_VALUE
*/
private long overflowFree(long delay) {
// ---- 方法首先会从当前调度线程池执行器的[工作队列]中获取头延迟,如果头延迟不为null,则获取头延迟的剩余延迟。
// 随后如果发现头延迟剩余延迟小于0且指定延迟减去头延迟剩余延迟的结果小于0,则将指定延迟赋值为
// Long.MAX_VALUE + 头延迟剩余延迟。
// ---- 头延迟剩余延迟小于0意味着头延迟已延迟到期,只是因为各方面的原因(包含但不限于系统调度、线程创建/唤醒
// 等方面的延迟)没有被调度线程池执行器及时的执行。而指定延迟减去头延迟剩余延迟的结果小于0则意味着结果超出
// 了Long.MAX_VALUE。超出的原因是因为头延迟的剩余延迟本身就为负数,因此指定延迟 - 头延迟剩余延迟时间的本质
// 是加法操作。在这种情况下如果指定延迟本身就很接近甚至等于Long.MAX_VALUE,就会导致两者相减的结果超过
// Long.MAX_VALUE。
// ---- 在结果超过Long.MAX_VALUE的情况下,方法会将指定延迟赋值为Long.MAX_VALUE + 头延迟剩余延迟,由于头延迟
// 剩余延迟为负数,因此该操作本质为减法操作。该操作的目的是避免当基于该指定延迟计算得到的触发时间所属的调度
// 未来任务与[工作队列]中的延迟(本质也是调度未来任务)进行剩余延迟比对时(所属调度未来任务加入[工作队列]时
// 发生),两者的差值不会出现超过Long.MAX_VALUE的情况。由于头延迟的剩余延迟是实际最小的,因此只要与之相减
// 得到的结果不会超过Long.MAX_VALUE,则与[工作队列]中的任意延迟进行比对就都不会导致超出的情况发生。
// ---- 已知在指定延时时间与头延迟剩余延迟相减的结果超过Long.MAX_VALUE的情况下,计算得到的触发时间为(已知的
// 是当前时间(2)会在当前时间(1)后获取,因此当前时间(2) >= 当前时间(1)):
// 触发时间 = 当前时间(1) + Long.MAX_VALUE + 头延迟剩余延迟(负数)
// = 当前时间(1) + Long.MAX_VALUE + (头延迟触发时间 - 当前时间(2))
// = 当前时间(1) + Long.MAX_VALUE + 头延迟触发时间 - 当前时间(2)
// <= Long.MAX_VALUE + 头延迟触发时间
// 而当触发时间所属调度未来任务入队与任意延迟进行剩余延迟比对时(这里直接拿头延迟进行比对),比对差值的计算
// 如下:
// 差值 <= (新调度未来任务触发时间 - 当前时间(3)) - (头延迟触发时间 - 当前时间(3))
// <= Long.MAX_VALUE + 头延迟触发时间 - 当前时间(3) - 头延迟触发时间 + 当前时间(3)
// <= Long.MAX_VALUE + 头延迟触发时间 - 头延迟触发时间
// <= Long.MAX_VALUE
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;
}
/**
* @throws RejectedExecutionException {@inheritDoc} 拒绝执行异常
* @throws NullPointerException {@inheritDoc} 空指针异常
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 调度
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 向当前调度线程池执行器递交在指定延迟后执行的可运行/任务,并返回追踪/获取可运行/任务执行状态/结果的调度未来。
* 由于在递交可运行/任务时没有传入用于承载可运行/任务执行结果的变量,因此调度未来实际无法获取可运行/任务的执
* 行结果,故而该方法返回的调度未来的get()方法将永远返回null。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法首先会判断指定可运行/任务及指定时间单位是否为null,是则直接抛出空指针异常;否则将指定延迟,单位作为
* 参数通过triggerTime(long delay)方法计算得到触发时间,并将指定可运行/任务和触发时间封装调度未来任务通过
* decorateTask(Runnable runnable, RunnableScheduledFuture<V> task)方法装饰获得最终要执行的调度未来任务交由
* delayedExecute(RunnableScheduledFuture<?> task)方法执行,并返回调度未来任务。
*/
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
// ---- 方法首先会判断指定可运行/任务及指定时间单位是否为null,是则直接抛出空指针异常;否则将指定延迟,单位作
// 为参数通过triggerTime(long delay)方法计算得到触发时间,并将指定可运行/任务和触发时间封装调度未来任务通过
// decorateTask(Runnable runnable, RunnableScheduledFuture<V> task)方法装饰获得最终要执行的调度未来任务交由
// delayedExecute(RunnableScheduledFuture<?> task)方法执行,并返回调度未来任务。
if (command == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<?> t = decorateTask(command, new ScheduledFutureTask<Void>(command, null, triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 调度
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 向当前调度线程池执行器递交在指定延迟后执行的可调用/任务,并返回追踪/获取可调用/任务执行状态/结果的调度未来。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法首先会判断指定可调用/任务及指定时间单位是否为null,是则直接抛出空指针异常;否则将指定延迟,单位作为
* 参数通过triggerTime(long delay)方法计算得到触发时间,并将指定可调用/任务和触发时间封装调度未来任务通过
* RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task)方法装饰获得最终要执
* 行的调度未来任务交由delayedExecute(RunnableScheduledFuture<?> task)方法执行,并返回调度未来任务。
*/
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
// ---- 方法首先会判断指定可调用/任务及指定时间单位是否为null,是则直接抛出空指针异常;否则将指定延迟,单位作
// 为参数通过triggerTime(long delay)方法计算得到触发时间,并将指定可调用/任务和触发时间封装调度未来任务通过
// decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task)方法装饰获得最终
// 要执行的调度未来任务交由delayedExecute(RunnableScheduledFuture<?> task)方法执行,并返回调度未来任务。
if (callable == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<V> t = decorateTask(callable, new ScheduledFutureTask<V>(callable, triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 按固定速率调度
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 向当前调度线程池执行器递交在指定初始延迟后按指定周期周期性执行的可运行/任务,并返回追踪/获取可运行/任务执行
* 状态/结果的调度未来。由于在递交可运行/任务时没有传入用于承载可运行/任务执行结果的变量,因此调度未来实际无法
* 获取可运行/任务的执行结果,故而该方法返回的调度未来的get()方法将永远返回null。但又因为该方法递交的可运行/任务
* 将在自身没有被取消/执行中没有抛出异常/当前调度线程池执行器没有被终止的情况下永远周期性地执行下去,因此调度未
* 来的get()方法要么因为上述情况抛出异常,要么因为无法获取到结果而无限等待。此外,即使可运行/任务的执行时间超过
* 周期,下次执行依然会在距离上次执行开始时间点的指定周期后开始,并且上次执行会被取消(虽然可能无法响应)。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法首先会判断指定可运行/任务及指定单位是否为null,是则直接抛出空指针异常;否则继续判断指定周期是否合法,
* 否则直接抛出非法参数异常。随后将指定初始延迟及单位为参数通过triggerTime(long delay)方法计算得到触发时间,并将
* 指定可运行/任务、触发时间及指定周期封装为调度未来任务通过
* decorateTask(Runnable runnable, RunnableScheduledFuture<V> task)方法装饰获得最终要执行的可运行调度未来,该可
* 运行调度未来会被保存在调度未来任务的[外部任务]中,作用是令两者建立关联,以使得通过调度未来任务可以直接找到
* 其被封装的可运行调度未来。可运行调度未来最终会交由delayedExecute(RunnableScheduledFuture<?> task)方法执行,
* 并被返回。
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
// ---- 方法首先会判断指定可运行/任务及指定单位是否为null,是则直接抛出空指针异常;否则继续判断指定周期是否
// 合法,否则直接抛出非法参数异常。随后将指定初始延迟及单位为参数通过triggerTime(long delay)方法计算得到触发
// 时间,并将指定可运行/任务、触发时间及指定周期封装为调度未来任务通过
// decorateTask(Runnable runnable, RunnableScheduledFuture<V> task)方法装饰获得最终要执行的可运行调度未来,该
// 可运行调度未来会被保存在调度未来任务的[外部任务]中,作用是令两者建立关联,以使得通过调度未来任务可以直接
// 找到其被封装的可运行调度未来。可运行调度未来最终会交由delayedExecute(RunnableScheduledFuture<?> task)方法
// 执行,并被返回。
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;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 随固定延迟调度
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 向当前调度线程池执行器递交在指定初始延迟后按指定延迟周期性执行的可运行/任务,并返回追踪/获取可运行/任务执行
* 状态/结果的调度未来。由于在递交可运行/任务时没有传入用于承载可运行/任务执行结果的变量,因此调度未来实际无法
* 获取可运行/任务的执行结果,故而该方法返回的调度未来的get()方法将永远返回null。但又因为该方法递交的可运行/任务
* 将在自身没有被取消/执行中没有抛出异常/当前调度线程池执行器没有被终止的情况下永远周期性地执行下去,因此调度未
* 来的get()方法要么因为上述情况抛出异常,要么因为无法获取到结果而无限等待。此外,如果可运行/任务的执行时间超过
* 周期,则下次执行会在距离上次执行结束时间点的指定延迟后开始。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法首先会判断指定可运行/任务及指定单位是否为null,是则直接抛出空指针异常;否则继续判断指定周期是否合法,
* 否则直接抛出非法参数异常。随后将指定初始延迟及单位为参数通过triggerTime(long delay)方法计算得到触发时间,并将
* 指定可运行/任务、触发时间及指定周期封装为调度未来任务通过
* decorateTask(Runnable runnable, RunnableScheduledFuture<V> task)方法装饰获得最终要执行的可运行调度未来,该可
* 运行调度未来会被保存在调度未来任务的[外部任务]中,作用是令两者建立关联,以使得通过调度未来任务可以直接找到
* 其被封装的可运行调度未来。可运行调度未来最终会交由delayedExecute(RunnableScheduledFuture<?> task)方法执行,
* 并被返回。
*/
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
// ---- 方法首先会判断指定可运行/任务及指定单位是否为null,是则直接抛出空指针异常;否则继续判断指定周期是否
// 合法,否则直接抛出非法参数异常。随后将指定初始延迟及单位为参数通过triggerTime(long delay)方法计算得到触发
// 时间,并将指定可运行/任务、触发时间及指定周期封装为调度未来任务通过
// decorateTask(Runnable runnable, RunnableScheduledFuture<V> task)方法装饰获得最终要执行的可运行调度未来,该
// 可运行调度未来会被保存在调度未来任务的[外部任务]中,作用是令两者建立关联,以使得通过调度未来任务可以直接
// 找到其被封装的可运行调度未来。可运行调度未来最终会交由delayedExecute(RunnableScheduledFuture<?> task)方法
// 执行,并被返回。
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;
}
/**
* Executes {@code command} with zero required delay. This has effect equivalent to
* {@link #schedule(Runnable, long, TimeUnit) schedule(command, 0, anyUnit)}. Note that inspections of the queue and of
* the list returned by {@code shutdownNow} will access the zero-delayed {@link ScheduledFuture}, not the
* {@code command} itself.
* 随着0获取延迟执行命令。该作用等价于schedule(command, 0, anyUnit)。注意:通过shutdownNow()方法返回的队列和列表
* 的检查将访问无延迟的调度未来,而非命令本身【即队列/列表中都是被命令被封装后的调度未来】。
* <p>
* A consequence of the use of {@code ScheduledFuture} objects is that
* {@link ThreadPoolExecutor#afterExecute afterExecute} is always called with a null second {@code Throwable}
* argument, even if the {@code command} terminated abruptly. Instead, the {@code Throwable} thrown by such a task
* can be obtained via {@link Future#get}.
* 使用调度未来的后果是ThreadPoolExecutor.afterExecute()方法经常随着空异常参数被调用,即使命令被突然中断【因为任
* 务在执行过程中抛出了异常,也会被调度未来内部捕捉,无法被执行器捕捉】。相反,任务抛出的异常可以通过调度未来的
* get()方法获取。
*
* @throws RejectedExecutionException at discretion of {@code RejectedExecutionHandler}, if the task cannot be
* accepted for execution because the executor has been shut down
* 拒绝执行异常:在拒绝执行异常处理器的判断中,如果任务因为执行器已被关闭而无法被接受
* 执行
* @throws NullPointerException {@inheritDoc} 空指针异常
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 执行
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 向当前调度线程池执行器递交指定延迟为0的可运行/任务。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法直接以0为指定延迟调用schedule(Runnable command, long delay, TimeUnit unit)方法实现。
*/
public void execute(Runnable command) {
schedule(command, 0, NANOSECONDS);
}
// Override AbstractExecutorService methods
// 重写抽象执行器服务方法
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 递交
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 向当前调度线程池执行器递交指定延迟为0的可运行/任务,并返回追踪/获取可运行/任务执行状态/结果的未来。由于在
* 递交可运行/任务时没有传入用于承载可运行/任务执行结果的变量,因此未来实际无法获取可运行/任务的执行结果,故
* 而该方法返回的未来的get()方法将永远返回null。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法直接以0为指定延迟调用schedule(Runnable command, long delay, TimeUnit unit)方法实现。
*/
public Future<?> submit(Runnable task) {
return schedule(task, 0, NANOSECONDS);
}
/**
* @throws RejectedExecutionException {@inheritDoc} 拒绝执行异常
* @throws NullPointerException {@inheritDoc} 空指针异常
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 递交
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 向当前调度线程池执行器递交指定延迟为0的可运行/任务,并返回追踪/获取可运行/任务执行状态/结果的未来。递交可
* 运行/任务时会同步传入一个用于承载可运行/任务执行结果的变量,该变量承载的可运行/任务执行结果即可直接获取,
* 也会向未来传递,因此该方法返回的未来的get()方法可返回可运行/任务的执行结果。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法直接以0为指定延迟调用schedule(Runnable command, long delay, TimeUnit unit)方法实现。
*/
public <T> Future<T> submit(Runnable task, T result) {
return schedule(Executors.callable(task, result), 0, NANOSECONDS);
}
/**
* @throws RejectedExecutionException {@inheritDoc} 拒绝执行异常
* @throws NullPointerException {@inheritDoc} 空指针异常
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 递交
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 向当前调度线程池执行器递交指定延迟为0的可调用/任务,并返回追踪/获取可调用/任务执行状态/结果的未来。递交可
* 调用/任务时会同步传入一个用于承载可调用/任务执行结果的变量,该变量承载的可调用/任务执行结果即可直接获取,
* 也会向未来传递,因此该方法返回的未来的get()方法可返回可调用/任务的执行结果。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法直接以0为指定延迟调用schedule(Callable<V> callable, long delay, TimeUnit unit)方法实现。
*/
public <T> Future<T> submit(Callable<T> task) {
return schedule(task, 0, NANOSECONDS);
}
/**
* Sets the policy on whether to continue executing existing periodic tasks even when this executor has been
* {@code shutdown}. In this case, these tasks will only terminate upon {@code shutdownNow} or after setting the policy
* to {@code false} when already shutdown. This value is by default {@code false}.
* 设置即使当执行器已被关闭时是否继续执行存在周期任务的策略。当已被关闭,在这种情况下,这些任务将只在
* shutdownNow()方法执行后或设置策略为false后终止。该值的默认值为false【默认调度线程池执行器是不允许周期任务在
* 关闭后执行的,因为周期执行等价于重复递交,而关闭后的执行器理论上不允许被递交的】。
*
* @param value if {@code true}, continue after shutdown, else don't 如果true,在关闭后继续,否则不执行
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 设置关闭后继续存在周期任务集策略
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 设置当调度线程池执行器被关闭后是否允许继续执行已递交的周期任务。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法首先会将[关闭后继续存在周期任务集]赋值为指定值,随后判断指定值是否为false。否则直接结束方法;是则继
* 续判断当前调度线程池是否已被关闭,是则调用onShutdown()方法清理[工作队列]中的所有周期任务;否则直接结束方法。
* @see #getContinueExistingPeriodicTasksAfterShutdownPolicy
*/
public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) {
// ---- 方法首先会将[关闭后继续存在周期任务集]赋值为指定值,随后判断指定值是否为false。否则直接结束方法;是
// 则继续判断当前调度线程池是否已被关闭,是则调用onShutdown()方法清理[工作队列]中的所有周期任务;否则直接结
// 束方法。
continueExistingPeriodicTasksAfterShutdown = value;
if (!value && isShutdown())
onShutdown();
}
/**
* Gets the policy on whether to continue executing existing periodic tasks even when this executor has been
* {@code shutdown}. In this case, these tasks will only terminate upon {@code shutdownNow} or after setting the
* policy to {@code false} when already shutdown. This value is by default {@code false}.
* 获取即使当执行已被关闭时是否继续执行周期任务的策略。在这种情况下,这些任务只有在停止之后,或在已关闭且设
* 置为false后才能终结。该值的默认值为false,
*
* @return {@code true} if will continue after shutdown 如果关闭后将继续则为true
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 获取关闭后继续存在周期任务集策略
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 判断当调度线程池执行器被关闭后是否继续执行周期任务,是则返回true;否则返回false。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法直接返回[关闭后继续存在周期任务集],该字段的默认值为true,因为延迟任务本质上属于已递交等待中的任务,
* 该状态的任务在SHUTDOWN(关闭)状态下应该是允许执行的。
* @see #setContinueExistingPeriodicTasksAfterShutdownPolicy
*/
public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() {
// 方法直接返回[关闭后继续存在周期任务集],该字段默认为false,因为周期任务的周期执行可以理解为一个任务被
// 重复递交,而在执行器的定义中被关闭后是不允许继续递交的,因此默认为false。
return continueExistingPeriodicTasksAfterShutdown;
}
/**
* Sets the policy on whether to execute existing delayed tasks even when this executor has been {@code shutdown}.
* In this case, these tasks will only terminate upon {@code shutdownNow}, or after setting the policy to
* {@code false} when already shutdown. This value is by default {@code true}.
* 设置即使当执行器已被关闭时是否继续执行存在延迟任务的策略。当已被关闭,在这种情况下,这些任务将只在
* shutdownNow()方法执行后或设置策略为false后终止。该值的默认值为true【默认调度线程池执行器是允许延迟任务在
* 关闭后执行的,因为延迟执行等价于等待执行,而关闭后的执行器理论上允许已递交等待中的任务执行的】。
*
* @param value if {@code true}, continue after shutdown, else don't 如果true,在关闭后继续,否则不执行
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 设置关闭后继续存在周期任务集策略
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 设置当调度线程池执行器被关闭后是否允许继续执行已递交的延迟任务。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法首先会将[关闭后继续执行延迟任务集]赋值为指定值,随后判断指定值是否为false。否则直接结束方法;是则继
* 续判断当前调度线程池是否已被关闭,是则调用onShutdown()方法清理[工作队列]中的所有延迟任务;否则直接结束方法。
* @see #getExecuteExistingDelayedTasksAfterShutdownPolicy
*/
public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) {
executeExistingDelayedTasksAfterShutdown = value;
if (!value && isShutdown())
onShutdown();
}
/**
* Gets the policy on whether to execute existing delayed tasks even when this executor has been {@code shutdown}.
* In this case, these tasks will only terminate upon {@code shutdownNow}, or after setting the policy to
* {@code false} when already shutdown. This value is by default {@code true}.
* 获取当当前执行器已被关闭时是否执行存在延迟任务的策略。在这种情况下,这些任务将只在停止之后,或者当执行器
* 已经关闭设置并策略为false后终止。该值默认为tue。
*
* @return {@code true} if will execute after shutdown 如果在关闭后将执行则返回true
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 获取关闭后执行存在延迟任务集策略
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 判断当线程池执行器被关闭后是否继续执行已存在的延迟任务,是则返回true;否则返回false。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* 方法直接返回[关闭后继续存在延迟任务集],该字段的默认值为true,因为延迟任务本质上属于已递交等待中的任务,该
* 状态的任务在SHUTDOWN(关闭)状态下应该是允许执行的。
* @see #setExecuteExistingDelayedTasksAfterShutdownPolicy
*/
public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() {
// 方法直接返回[关闭后继续存在延迟任务集],该字段的默认值为true,因为延迟任务本质上属于已递交等待中的任务,
// 该状态的任务在SHUTDOWN(关闭)状态下应该是允许执行的。
return executeExistingDelayedTasksAfterShutdown;
}
/**
* Sets the policy on whether cancelled tasks should be immediately removed from the work queue at time of cancellation.
* This value is by default {@code false}.
* 设置已取消任务是否应该在取消时立即从工作队列中移除的策略。该值默认为false。
*
* @param value if {@code true}, remove on cancellation, else don't 如果为true,取消时移除;否则不移除
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 设置取消时移除策略
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 设置任务取消时是否从当前调度线程池执行器的工作队列中移除
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法直接将[取消时移除]赋值为指定值。
* @see #getRemoveOnCancelPolicy
* @since 1.7
*/
public void setRemoveOnCancelPolicy(boolean value) {
removeOnCancel = value;
}
/**
* Gets the policy on whether cancelled tasks should be immediately removed from the work queue at time of cancellation.
* This value is by default {@code false}.
* 获取已取消任务在取消时是否立即从工作队列中移除的策略。该值的默认值为false。
*
* @return {@code true} if cancelled tasks are immediately removed from the queue 如果为true则立即从队列中移除
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 获取取消时移除策略
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 判断任务取消时是否从当前调度线程池执行器的工作队列中移除,是则返回true;否则返回false。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法直接返回[取消时移除]。
* @see #setRemoveOnCancelPolicy
* @since 1.7
*/
public boolean getRemoveOnCancelPolicy() {
return removeOnCancel;
}
/**
* Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
* Invocation has no additional effect if already shut down.
* 启动一个有序关闭,先前已递交的任务会被执行,但无新任务会被接受。如果已经关闭调用没有额外作用。
* <p>
* This method does not wait for previously submitted tasks to complete execution. Use
* {@link #awaitTermination awaitTermination} to do that.
* 方法不等待先前已递交任务完成执行。可以使用awaitTermination()方法做到这一点。
* <p>
* If the {@code ExecuteExistingDelayedTasksAfterShutdownPolicy} has been set {@code false}, existing delayed tasks
* whose delays have not yet elapsed are cancelled. And unless the
* {@code ContinueExistingPeriodicTasksAfterShutdownPolicy} has been set {@code true}, future executions of existing
* periodic tasks will be cancelled.
* 如果关闭后执行存在延迟任务集已被设置为false,则已存在延迟任务的延迟还未消逝就会被取消。并且除非关闭后继续存
* 在周期任务集已被设置为true,否则已存在周期任务的未来执行也将被取消。
*
* @throws SecurityException {@inheritDoc} 安全异常
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 关闭
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 关闭当前调度线程池执行器,关闭后当前调度线程池执行器会拒绝新任务递交,并根据相关策略决定是否取消已存在的旧
* 任务。此外,即使有旧任务没有被取消,方法也不会等待旧任务执行结束(完成/异常/取消)后返回。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法直接调用父类的shutdown()方法实现。
*/
public void shutdown() {
super.shutdown();
}
/**
* Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks
* that were awaiting execution.
* 尝试关闭所有活跃地执行任务,中止等待中任务的执行,并且返回等待执行任务的列表。
* <p>
* This method does not wait for actively executing tasks to terminate. Use {@link #awaitTermination awaitTermination}
* to do that.
* 该方法不等待活跃执行任务中止。使用awaitTermination()方法可以做到这一点。
* <p>
* There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. This implementation
* cancels tasks via {@link Thread#interrupt}, so any task that fails to respond to interrupts may never terminate.
* 除了尽做大努力尝试停止活跃执行任务外没有任何保证。该实现通过线程中断取消任务,所以任意任务失败响应中断都可能
* 永不中止。
*
* @return list of tasks that never commenced execution. Each element of this list is a {@link ScheduledFuture}, including
* those tasks submitted using {@code execute}, which are for scheduling purposes used as the basis of a zero-delay
* {@code ScheduledFuture}.
* 从未开始执行的任务列表。列表中的每个元素都是一个调度未来,包括使用execute()方法递交的任务,这种情况下处于调
* 度目的用作一个零延迟调度未来的基础【即通过execute()方法递交的任务会封装为一个零延迟的延迟型调度未来】。
* @throws SecurityException {@inheritDoc} 安全异常
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 立刻关闭(停止)
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 关闭当前调度线程池执行器,关闭后当前调度线程池执行器会拒绝新任务递交,并且无论相关策略如何,已存在的旧任务
* 都会被尝试取消,并返回未执行(等待中)的旧任务列表。此外,即使有旧任务没有响应取消,方法也不会等待旧任务执
* 行结束(完成/异常/取消)后返回。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法直接调用父类的shutdownNow()方法实现。
*/
public List<Runnable> shutdownNow() {
return super.shutdownNow();
}
/**
* Returns the task queue used by this executor. Each element of this queue is a {@link ScheduledFuture}, including
* those tasks submitted using {@code execute} which are for scheduling purposes used as the basis of a zero-delay
* {@code ScheduledFuture}. Iteration over this queue is <em>not</em> guaranteed to traverse tasks in the order in
* which they will execute.
* 返回当前执行器所使用的任务队列。队列中的每个元素都是调度未来,包括使用execute()方法递交的任务,这种情况下
* 处于调度目的用作一个零延迟调度未来的基础。迭代当前队列不保证按任务执行的顺序遍历它们。
*
* @return the task queue 任务队列
* @Description: ------------------------------------------------------------- 名称 -------------------------------------------------------------
* 获取队列
* @Description: ------------------------------------------------------------- 作用 -------------------------------------------------------------
* 获取当前调度线程池执行器的工作队列。工作队列中的每个任务都是调度未来,并且无法保证按任务的执行顺序对之进行
* 遍历(因为工作队列默认为优先级阻塞队列)。
* @Description: ------------------------------------------------------------- 逻辑 -------------------------------------------------------------
* ---- 方法直接调用父类的getQueue()方法实现。
*/
public BlockingQueue<Runnable> getQueue() {
return super.getQueue();
}
/**
* Specialized delay queue. To mesh with TPE declarations, this class must be declared as a BlockingQueue<Runnable>
* even though it can only hold RunnableScheduledFutures.
* 指定的延迟队列。以匹配TPE声明,该类必须被声明为一个阻塞队列,即使它只能持有可运行调度未来。
*/
static class DelayedWorkQueue extends AbstractQueue<Runnable> implements BlockingQueue<Runnable> {
/*
* A DelayedWorkQueue is based on a heap-based data structure like those in DelayQueue and PriorityQueue, except
* that every ScheduledFutureTask also records its index into the heap array. This eliminates the need to find a task
* upon cancellation, greatly speeding up removal (down from O(n) to O(log n)), and reducing garbage retention that
* would otherwise occur by waiting for the element to rise to top before clearing. But because the queue may also
* hold RunnableScheduledFutures that are not ScheduledFutureTasks, we are not guaranteed to have such indices
* available, in which case we fall back to linear search. (We expect that most tasks will not be decorated, and that
* the faster cases will be much more common.)
* 一个延迟工作队列基于类似于延迟队列及优先级队列的堆数据结构,除了每个调度未来任务也记录它在堆数组中的索引。
* 这消除了在取消时查找任务的需要,极大地加快了删除速度(从O(n)降至O(log n)),并减少了垃圾保留,否则会等待元素
* 上升到顶部再进行清除。但是因为队列可能还持有不是调度未来任务的可运行调度未来(这是因为包装的原因),
* 我们无法保证如此索引可用,在这种情况下我们后退回线性查询。(我们期望大多数任务不被包装,并且快速情况将会
* 是普遍的【即延迟工作队列中的任务大多都是调度未来任务或其子类】)
* All heap operations must record index changes -- mainly within siftUp and siftDown. Upon removal, a task's
* heapIndex is set to -1. Note that ScheduledFutureTasks can appear at most once in the queue (this need not be
* true for other kinds of tasks or work queues), so are uniquely identified by heapIndex.
* 所有堆操作必须记录索引改变 -- 主要在上/下排序中。在移除后,一个任务的堆索引将被设置为-1。注意调度未来任务
* 在队列中最多只能出现一次(对于其他类型的任务或工作队列,则不必如此),所以通过堆内存唯一鉴别。
*/
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 初始容量
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 持有延迟工作队列的初始容量16
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ----
*/
private static final int INITIAL_CAPACITY = 16;
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 队列
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 持有当前延迟工作队列用于存放任务的元素数组
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ----
*/
private RunnableScheduledFuture<?>[] queue = new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 锁
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 持有保护当前延迟工作队列线程安全的重入锁
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ----
*/
private final ReentrantLock lock = new ReentrantLock();
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 大小
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 持有当前延迟工作队列中保存的任务总数
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ----
*/
private int size = 0;
/**
* Thread designated to wait for the task at the head of the queue. This variant of the Leader-Follower pattern
* (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to minimize unnecessary timed waiting. When a thread
* becomes the leader, it waits only for the next delay to elapse, but other threads await indefinitely. The leader
* thread must signal some other thread before returning from take() or poll(...), unless some other thread becomes
* leader in the interim. Whenever the head of the queue is replaced with a task with an earlier expiration time, the
* leader field is invalidated by being reset to null, and some waiting thread, but not necessarily the current leader,
* is signalled. So waiting threads must be prepared to acquire and lose leadership while waiting.
* 领导者被设计用于等待队列的头任务。这是领导者 - 跟随者模式的变种
* (具体查看:http://www.cs.wustl.edu/~schmidt/POSA/POSA2/)用于最小限度定时等待。当一个线程变为领导者时,
* 它值为下个延迟到期等待,但其它线程无限期地等待。领导者线程必须在从take()或poll(...)方法中返回前发送信号至其
* 它线程,除非某些其它线程在此期间变为领导者【例如有新的剩余延迟时间更低的任务入队,使得其它线程为止专属
* 等待成为新的领导者而导致当前线程失去了领导者身份】。无论队列的头任务何时被一个到期时间更早的任务顶替,
* 领导者字段都会无效并被重设为null,且某些等待线程,但不一定是当前领导者收到信号。所以等待线程在等待期间必
* 须准备好获取和失去领导者地位。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 领导者
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 持有专属等待队列头任务剩余延迟到期的线程
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ----
*/
private Thread leader = null;
/**
* Condition signalled when a newer task becomes available at the head of the queue or a new thread may need to
* become leader.
* 当一个更新的任务编程在队列的头部变得可用或一个新线程可能需要变成领导者时条件通知。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 可用
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 保存所有等待队列中存在延迟到期任务的线程,并作为在队列中存在延迟到期任务时唤醒等待线程的入口/操作点
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ----
*/
private final Condition available = lock.newCondition();
/**
* Sets f's heapIndex if it is a ScheduledFutureTask.
* 如果f是调度未来任务则设置f的堆指针
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 设置指针
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 为指定调度任务未来设置指定堆索引
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先会判断指定可运行调度未来是否是调度未来任务类型,否则直接结束方法;是则将至[堆指针]赋值为指定
* 索引。
*/
private void setIndex(RunnableScheduledFuture<?> f, int idx) {
// ---- 方法首先会判断指定可运行调度未来是否是调度未来任务类型,否则直接结束方法;是则将至[堆指针]赋值为指
// 定索引。
if (f instanceof ScheduledFutureTask)
((ScheduledFutureTask) f).heapIndex = idx;
}
/**
* Sifts element added at bottom up to its heap-ordered spot. Call only when holding lock.
* 筛选新增的元素从底部上升至堆排序为止。只在是持有锁时调用。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 上排序
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 将指定可运行调度未来从指定索引位置上排序至符合小顶堆规则的相应位置
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会根据(子索引 - 1)/2的规则计算指定索引的父索引,随后将指定可运行调度未来与[工作队列]中父索引位置的
* 可运行调度未来进行比较,如果指定可运行调度未来的剩余延迟大于父索引位置的可运行调度未来则直接结束;否则将
* 父索引位置的可运行调度未来迁移至指定索引位置,相当于将指定可运行调度未来上排序到其父索引位置。并调用
* setIndex(RunnableScheduledFuture<?> f, int idx)方法为之重设[堆索引](如果其是调度未来任务的话),最后将指定索
* 引赋值为其父索引。重复上述流程,直至指定可运行调度未来的剩余延迟时间大于其父索引位置的可运行调度未来或已
* 排序到堆的顶部为止。方法的最后会将指定可运行调度未来存入被赋予新值的指定索引位置中,表示指定可运行调度未
* 来已正式完成排序,并调用setIndex(RunnableScheduledFuture<?> f, int idx)方法为之设置[堆索引]。
*/
private void siftUp(int k, RunnableScheduledFuture<?> key) {
// ---- 方法会根据(子索引 - 1)/2的规则计算指定索引的父索引,随后将指定可运行调度未来与[工作队列]中父索引位
// 置的可运行调度未来进行比较,如果指定可运行调度未来的剩余延迟大于父索引位置的可运行调度未来则直接结束;
// 否则将父索引位置的可运行调度未来迁移至指定索引位置,相当于将指定可运行调度未来上排序到其父索引位置。
// 并调用setIndex(RunnableScheduledFuture<?> f, int idx)方法为之重设[堆索引](如果其是调度未来任务的话),最
// 后将指定索引赋值为其父索引。重复上述流程,直至指定可运行调度未来的剩余延迟时间大于其父索引位置的可运
// 行调度未来或已排序到堆的顶部为止。方法的最后会将指定可运行调度未来存入被赋予新值的指定索引位置中,表
// 示指定可运行调度未来已正式完成排序,并调用setIndex(RunnableScheduledFuture<?> f, int idx)方法为之设置[堆索
// 引]。
while (k > 0) {
int parent = (k - 1) >>> 1;
RunnableScheduledFuture<?> e = queue[parent];
if (key.compareTo(e) >= 0)
break;
queue[k] = e;
setIndex(e, k);
k = parent;
}
queue[k] = key;
setIndex(key, k);
}
/**
* Sifts element added at top down to its heap-ordered spot. Call only when holding lock.
* 筛选新增的元素从顶部下降至堆排序位置。只在是持有锁时调用。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 下排序
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 将指定可运行调度未来从指定索引位置下排序至符合小顶堆规则的相应位置
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先会通过[大小]/2得到半数,指定索引只有在小于半数的情况下才会进行下排序。这是因为子索引 = 父索引
* * 2 + 1/2,所以在指定索引 >= 半数的情况下是无法进行下排序的,可以直接结束方法。
* ---- 在指定索引小于半数的情况下,方法会循环执行以下操作:首先,方法会计算得到指定索引的左/右子索引,随后
* 将指定可运行调度未来与左/右子索引位置的可运行调度未来进行剩余延迟的对比。指定可运行调度未来的剩余延迟 <=
* 左/右子索引位置的可运行调度未来,则直接结束循环;否则将左/右子索引位置的可运行调度未来中剩余延迟较小的一
* 个迁移至指定索引位置中,相当于将指定可运行调度未来下排序到其子索引位置。并调用
* setIndex(RunnableScheduledFuture<?> f, int idx)方法为之重设[堆索引](如果其是调度未来任务的话),最后将指定索
* 引赋值为被克运行调度未来被迁移的索引。上述循环会持续到指定可运行调度未来的剩余延迟 > 左/右子索引位置的可
* 运行调度未来的剩余延迟或指定延迟 >= 半数为止。
* ---- 方法最后会将指定可运行调度未来保存在赋予新值的指定索引位置中,表示可运行调度未来已正式完成下排序,并
* 调用setIndex(RunnableScheduledFuture<?> f, int idx)方法为之设置[堆索引]。
*/
private void siftDown(int k, RunnableScheduledFuture<?> key) {
// ---- 方法首先会通过[大小]/2得到半数,指定索引只有在小于半数的情况下才会进行下排序。这是因为子索引 = 父
// 索引 * 2 + 1/2,所以在指定索引 >= 半数的情况下是无法进行下排序的,可以直接结束方法。
// ---- 在指定索引小于半数的情况下,方法会循环执行以下操作:首先,方法会计算得到指定索引的左/右子索引,随
// 随后将指定可运行调度未来与左/右子索引位置的可运行调度未来进行剩余延迟的对比。指定可运行调度未来的剩余
// 延迟 <= 左/右子索引位置的可运行调度未来,则直接结束循环;否则将左/右子索引位置的可运行调度未来中剩余
// 延迟较小的一个迁移至指定索引位置中,相当于将指定可运行调度未来下排序到其子索引位置。并调用
// setIndex(RunnableScheduledFuture<?> f, int idx)方法为之重设[堆索引](如果其是调度未来任务的话),最后将指
// 定索引赋值为被克运行调度未来被迁移的索引。上述循环会持续到指定可运行调度未来的剩余延迟 > 左/右子索引位
// 置的可运行调度未来的剩余延迟或指定延迟 >= 半数为止。
// ---- 方法最后会将指定可运行调度未来保存在赋予新值的指定索引位置中,表示可运行调度未来已正式完成下排序,
// 并调用setIndex(RunnableScheduledFuture<?> f, int idx)方法为之设置[堆索引]。
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
RunnableScheduledFuture<?> c = queue[child];
int right = child + 1;
if (right < size && c.compareTo(queue[right]) > 0)
c = queue[child = right];
if (key.compareTo(c) <= 0)
break;
queue[k] = c;
setIndex(c, k);
k = child;
}
queue[k] = key;
setIndex(key, k);
}
/**
* Resizes the heap array. Call only when holding lock.
* 调整堆数组的大小。只当持有锁时调用。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 成长
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建一个容量为旧元素数组1.5倍的新元素数组,并将旧元素数组中的所有元素按原顺序迁移至新元素数组。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会基于[队列]的长度,即旧容量通过公式旧容量 * 1.5得到新容量。如果新容量小于0,则意味着新容量超出了
* int的最大值,此时直接将新容量赋值为Integer.MAX_VALUE。
* ---- 得到新容量后,通过Arrays.copyOf(T[] original, int newLength)方法完成新[队列]的创建及任务的迁移。
*/
private void grow() {
// ---- 方法会基于[队列]的长度,即旧容量通过公式旧容量 * 1.5得到新容量。如果新容量小于0,则意味着新容量超出
// 了int的最大值,此时直接将新容量赋值为Integer.MAX_VALUE。
// ---- 得到新容量后,通过Arrays.copyOf(T[] original, int newLength)方法完成新[队列]的创建及任务的迁移。
int oldCapacity = queue.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50%
if (newCapacity < 0) // overflow
newCapacity = Integer.MAX_VALUE;
queue = Arrays.copyOf(queue, newCapacity);
}
/**
* Finds index of given object, or -1 if absent.
* 找到指定对象的索引,如果不存在则返回-1。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 索引
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建一个容量为旧元素数组1.5倍的新元素数组,并将旧元素数组中的所有元素按原顺序迁移至新元素数组。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先会判断指定对象是否为null,是则直接返回-1;否则继续判断指定对象是否为调度未来任务。是则直接获
* 取其[堆索引]并判断是否合法,以及[堆索引]位置的任务是否为指定对象,是则直接返回[堆索引];否则直接返回-1。
* ---- 如果指定对象不是调度未来任务,则按顺序遍历整个[队列],当指定对象等于某个对象时返回相应索引。而如果遍
* 历结束后都没有发现相等的对象则直接返回-1。
*/
private int indexOf(Object x) {
// ---- 方法首先会判断指定对象是否为null,是则直接返回-1;否则继续判断指定对象是否为调度未来任务。是则直接
// 获取其[堆索引]并判断是否合法,以及[堆索引]位置的任务是否为指定对象,是则直接返回[堆索引];否则直接返回
// -1。
// ---- 如果指定对象不是调度未来任务,则按顺序遍历整个[队列],当指定对象等于某个对象时返回相应索引。而如果
// 遍历结束后都没有发现相等的对象则直接返回-1。
if (x != null) {
if (x instanceof ScheduledFutureTask) {
int i = ((ScheduledFutureTask) x).heapIndex;
// Sanity check; x could conceivably be a ScheduledFutureTask from some other pool.
// 合理性检查;x可能是来自于某些其它池中的调度计划未来。
if (i >= 0 && i < size && queue[i] == x)
return i;
} else {
for (int i = 0; i < size; i++)
if (x.equals(queue[i]))
return i;
}
}
return -1;
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 包含
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 判断当前延迟工作队列是否存在指定对象,是则返回true;否则返回false。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会在加锁的情况下调用indexOf(Object x)方法判断返回值是否不为-1,是则说明存在,返回true;否则说明不
* 存在,返回false。
*/
public boolean contains(Object x) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return indexOf(x) != -1;
} finally {
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 移除
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 从当前延迟工作队列中移除指定对象,成功则返回true;否则返回false。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会在加锁的情况下通过indexOf(Object x)方法获取指定对象在当前延迟工作队列中的索引,如果索引为-1,意
* 味指定对象在当前延迟工作队列中不存在,直接返回false;否则意味着存在,需要将之从中移除。
* ---- 移除的第一步是调用setIndex(RunnableScheduledFuture<?> f, int idx)方法将指定对象的[堆索引](如果指定对象是
* 调度未来任务的话)设置为-1,因为-1意味着这其在延迟工作队列中不存在。随后递减[大小],并将递减后的[大小]作为
* 索引获取该位置的可运行调度未来再将位置至null,用于填充被移除后的指定对象。我们需要对填充的元素进行下/上排
* 序,以确保填充任务被排序到合适的位置上。最后返回true,表示指定对象移除完成。
*/
public boolean remove(Object x) {
// ---- 方法会在加锁的情况下通过indexOf(Object x)方法获取指定对象在当前延迟工作队列中的索引,如果索引为-1,
// 意味指定对象在当前延迟工作队列中不存在,直接返回false;否则意味着存在,需要将之从中移除。
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = indexOf(x);
if (i < 0)
return false;
// ---- 移除的第一步是调用setIndex(RunnableScheduledFuture<?> f, int idx)方法将指定对象的[堆索引](如果指
// 定对象是调度未来任务的话)设置为-1,因为-1意味着这其在延迟工作队列中不存在。随后递减[大小],并将
// 递减后的[大小]作为索引获取该位置的可运行调度未来再将位置至null,用于填充被移除后的指定对象。我们需
// 要对填充的元素进行下/上排序,以确保填充任务被排序到合适的位置上。最后返回true,表示指定对象移除完
// 成。
setIndex(queue[i], -1);
int s = --size;
RunnableScheduledFuture<?> replacement = queue[s];
queue[s] = null;
if (s != i) {
siftDown(i, replacement);
if (queue[i] == replacement)
siftUp(i, replacement);
}
return true;
} finally {
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 大小
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 获取当前延迟工作队列中的任务总数
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会在加锁的情况下直接返回[大小]实现。
*/
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return size;
} finally {
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 是否为空
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 获取当前延迟工作队列中的任务总数是否为0,是则返回true;否则返回false。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会直接判断[大小]是否为0实现。
*/
public boolean isEmpty() {
return size() == 0;
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 剩余容量
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 获取当前延迟工作队列的剩余容量,由于延迟工作队列类是无界队列,因此该方法会固定返回Integer.MAX_VALUE。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法直接返回Integer.MAX_VALUE实现。
*/
public int remainingCapacity() {
return Integer.MAX_VALUE;
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 窥视
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 从当前延迟工作队列的头部获取元素,如果当前延迟工作队列存在元素则返回头元素;否则直接返回null。注意!该方
* 法获取的是元素,而非延迟到期元素。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会在锁的保护下直接返回[队列]的头元素。
*/
public RunnableScheduledFuture<?> peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return queue[0];
} finally {
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 新增
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 向当前延迟工作队列的尾部插入指定元素,并根据指定元素的剩余延迟按小顶堆规则将之排序到合适位置。该方法是尾
* 部插入方法“异常”形式的实现,当当前延迟工作队列存在剩余容量时插入;否则直接抛出非法状态异常。虽说定义如此,
* 但实际由于延迟工作队列类是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会抛出非法状态异常,而
* 只会在堆内存不足时抛出内存溢出错误。由于延迟工作队列类基于数组实现,因此最大容量实际还受限于
* Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法直接调用offer(e)方法实现。
*/
public boolean add(Runnable e) {
return offer(e);
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 提供
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 向当前延迟工作队列的尾部插入指定元素,并根据指定元素的剩余延迟按小顶堆规则将之排序到合适位置。该方法是尾
* 部插入方法“特殊值”形式的实现,当当前延迟工作队列存在剩余容量时插入并返回true;否则直接返回false。虽说定义
* 如此,但实际由于延迟工作队列类是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会抛出非法状态异
* 常,而只会在堆内存不足时抛出内存溢出错误。由于延迟工作队列类基于数组实现,因此最大容量实际还受限于
* Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先会判断指定元素是否为null,为null则直接抛出空指针异常;否则将指定元素转换为可运行调度未来。
* ---- 随后方法会进行加锁以确保并发的发生,并判断[队列]中是否还有剩余容量用于插入指定元素。没有则直接调用
* grow()方法对[队列]进行1.5倍的扩容,随后递增[大小]。这之后便将指定元素插入[队列]的尾部,并更新其[堆索引]。这
* 其中的细节操作是:如果指定元素是[队列]中的首个元素,则只需直接插入即可并会更新[堆索引]即可;但如果不是首个
* 元素,则还需要进行上排序将的指定元素依据小顶堆规则排序达到合适的位置上。
* ---- 入队即排序结束后,如果指定元素被排序到了[队列]的头部,说明指定元素是剩余延迟最小的元素。这种情况下可能
* 需要对领导者进行更新操作,因此这意味着指定元素可能的可以直接获取或等待的时间更小。因此会将[领导者]赋值为null,
* 并从[可用]中唤醒一个移除线程以令其尝试成为新的[领导者]。最后直接返回true表示方法结束。
*/
public boolean offer(Runnable x) {
// ---- 方法首先会判断指定元素是否为null,为null则直接抛出空指针异常;否则将指定元素转换为可运行调度未来。
if (x == null)
throw new NullPointerException();
RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>) x;
// ---- 随后方法会进行加锁以确保并发的发生,并判断[队列]中是否还有剩余容量用于插入指定元素。没有则直接调用
// grow()方法对[队列]进行1.5倍的扩容,随后递增[大小]。这之后便将指定元素插入[队列]的尾部,并更新其[堆索引]。
// 这其中的细节操作是:如果指定元素是[队列]中的首个元素,则只需直接插入即可并会更新[堆索引]即可;但如果不
// 是首个元素,则还需要进行上排序将的指定元素依据小顶堆规则排序达到合适的位置上。
// ---- 入队即排序结束后,如果指定元素被排序到了[队列]的头部,说明指定元素是剩余延迟最小的元素。这种情况下
// 可能需要对领导者进行更新操作,因此这意味着指定元素可能的可以直接获取或等待的时间更小。因此会将[领导者]
// 赋值为null,并从[可用]中唤醒一个移除线程以令其尝试成为新的[领导者]。最后直接返回true表示方法结束。
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = size;
if (i >= queue.length)
grow();
size = i + 1;
if (i == 0) {
queue[0] = e;
setIndex(e, 0);
} else {
siftUp(i, e);
}
if (queue[0] == e) {
leader = null;
available.signal();
}
} finally {
lock.unlock();
}
return true;
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 放置
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 向当前延迟工作队列的尾部插入指定元素,并根据指定元素的剩余延迟按小顶堆规则将之排序到合适位置。该方法是尾
* 部插入方法“阻塞”形式的实现,当当前延迟工作队列存在剩余容量时插入;否则无限等待至存在剩余容量为止。虽说定
* 义如此,但实际由于延迟工作队列类是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会抛出非法状态
* 异常,而只会在堆内存不足时抛出内存溢出错误。由于延迟工作队列类基于数组实现,因此最大容量实际还受限于
* Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法直接调用offer(e)方法实现。
*/
public void put(Runnable e) {
offer(e);
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 提供
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 向当前延迟工作队列的尾部插入指定元素,并根据指定元素的剩余延迟按小顶堆规则将之排序到合适位置。该方法是尾
* 部插入方法“超时”形式的实现,当当前延迟工作队列存在剩余容量时插入并返回true;否则在指定等待时间内有限等待
* 至存在剩余容量为止,超出指定等待时间则返回false。虽说定义如此,但实际由于延迟工作队列类是真正的无界队列,
* 最大容量只受限于堆内存的大小,故而永远不会抛出非法状态异常,而只会在堆内存不足时抛出内存溢出错误。由于延
* 迟工作队列类基于数组实现,因此最大容量实际还受限于Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实
* 际实现上的限制,会手动抛出内存溢出错误。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法直接调用offer(e)方法实现。
*/
public boolean offer(Runnable e, long timeout, TimeUnit unit) {
return offer(e);
}
/**
* Performs common bookkeeping for poll and take: Replaces first element with last and sifts it down. Call only when
* holding lock.
* 为poll和take方法执行公共薄记:随着最后和下排序替换首个元素。只在持有锁时调用。
*
* @param f the task to remove and return 用于移除并返回的任务
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 结束轮询
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 将指定元素从当前延迟工作队列中移除并对剩余元素按小顶堆规则进行重排序。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先会递减[总数],表示指定可运行调度未来已被移除。随后获取[队列]中的最后可运行调度未来用来填充指定
* 可运行调度未来的位置,如果指定可运行调用未来不是头任务的,则对用于填充的最后可运行调度未来进行下排序按小
* 顶堆的规则排序到合适为止,最后将指定可运行调用未来的[堆索引]设置为-1并返回。
*/
private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
// ---- 方法首先会递减[总数],表示指定可运行调度未来已被移除。随后获取[队列]中的最后可运行调度未来用来填充
// 指定可运行调度未来的位置,如果指定可运行调用未来不是头任务的,则对用于填充的最后可运行调度未来进行下
// 排序按小顶堆的规则排序到合适为止,最后将指定可运行调用未来的[堆索引]设置为-1并返回。
int s = --size;
RunnableScheduledFuture<?> x = queue[s];
queue[s] = null;
if (s != 0)
siftDown(0, x);
setIndex(f, -1);
return f;
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 轮询
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 从当前延迟工作队列的头部移除并获取剩余延迟最小的延迟到期元素,并触发后续元素的重排序。该方法是头部移除方法
* “特殊值”形式的实现,当当前延迟工作队列存在延迟到期元素时移除并返回头延迟到期元素;否则返回null。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会在加锁的情况下获取[队列]中的头元素,如果头元素不存在或者延迟未到期则直接返回null;否则调用
* finishPoll(RunnableScheduledFuture<?> f)方法移除头元素,并以[队列]的最后元素进行原位填充完成下排序,以保证剩
* 余元素的符合小顶堆排序后将原头元素返回。
*/
public RunnableScheduledFuture<?> poll() {
// ---- 方法会在加锁的情况下获取[队列]中的头元素,如果头元素不存在或者延迟未到期则直接返回null;否则调用
// finishPoll(RunnableScheduledFuture<?> f)方法移除头元素,并以[队列]的最后元素进行原位填充完成下排序,以保
// 证剩余元素的符合小顶堆排序后将原头元素返回。
final ReentrantLock lock = this.lock;
lock.lock();
try {
RunnableScheduledFuture<?> first = queue[0];
if (first == null || first.getDelay(NANOSECONDS) > 0)
return null;
else
return finishPoll(first);
} finally {
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 拿取
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 从当前延迟工作队列的头部移除并获取剩余延迟最小的延迟到期元素,并触发后续元素的重排序。该方法是头部移除方
* 法“阻塞”形式的实现,当当前延迟工作队列存在延迟到期元素时移除并返回头延迟到期元素;否则无限等待至存在延迟
* 到期元素为止。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会在加锁(中断后会抛出中断异常)的情况下从[队列]中获取头元素,并判断头元素是否存在,不存在则令当
* 前线程进入无限等待状态,直至因为存在延迟到期元素或专属等到头元素延迟到期而唤醒;否则继续判断头元素是否延
* 迟到期,是则直接调用finishPoll(RunnableScheduledFuture<?> f)方法移除该头延迟到期元素并完成对后续元素的排序后
* 结束方法;否则继续判断当前[领导者]是否存在。是则意味该头元素已被专属等待,当前线程进入无限等待状态;否则
* 令当前线程对之进行专属等待,即令当前线程进入有限等待状态,且等待时间为头元素的剩余等待时间,以确保头元素
* 延迟到期后当前线程可以(接近)实时的将之移除。领导者无法保证头元素一定会被自身移除,也可能被适时到来/唤
* 醒的外部/内部线程移除。
* ---- 当前线程如果在专属等待头元素延迟到期期间被中断则将抛出中断异常,但是在排除中断异常之前,如果发现自身
* 还是[领导者],则需要将[领导者]赋值为null表示自身退出领导者地位。因为被中断后当前线程将退出该方法,如果不主
* 动失去领导者地位,则后续的移除者将无法对头元素进行专属等待,这会导致头元素延迟到期后可能无法再有移除者等
* 待的情况下被实时移除。
* ---- 无论当前移除者是正常/异常的退出,在退出之前如果发现当前延迟工作队列还存在新头元素且[领导者]不存在,则
* 需要唤醒一个等待中的移除者,目的是令之对新头元素进行专属等待。当然,前提是存在等待中的移除者,否则该操作
* 将没有任何实际效果。
*/
public RunnableScheduledFuture<?> take() throws InterruptedException {
// ---- 方法会在加锁(中断后会抛出中断异常)的情况下从[队列]中获取头元素,并判断头元素是否存在,不存在则令
// 当前线程进入无限等待状态,直至因为存在延迟到期元素或专属等到头元素延迟到期而唤醒;否则继续判断头元素
// 是否延迟到期,是则直接调用finishPoll(RunnableScheduledFuture<?> f)方法移除该头延迟到期元素并完成对后续元
// 素的排序后结束方法;否则继续判断当前[领导者]是否存在。是则意味该头元素已被专属等待,当前线程进入无限等
// 待状态;否则令当前线程对之进行专属等待,即令当前线程进入有限等待状态,且等待时间为头元素的剩余等待时
// 间,以确保头元素延迟到期后当前线程可以(接近)实时的将之移除。领导者无法保证头元素一定会被自身移除,
// 也可能被适时到来/唤醒的外部/内部线程移除。
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (; ; ) {
RunnableScheduledFuture<?> first = queue[0];
if (first == null)
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)
return finishPoll(first);
// don't retain ref while waiting
// 不要在等待期间保留引用
first = null;
if (leader != null)
available.await();
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;
// ---- 当前线程如果在专属等待头元素延迟到期期间被中断则将抛出中断异常,但是在排除中断异常之前,
// 如果发现自身还是[领导者],则需要将[领导者]赋值为null表示自身退出领导者地位。因为被中断后当前
// 线程将退出该方法,如果不主动失去领导者地位,则后续的移除者将无法对头元素进行专属等待,这会
// 导致头元素延迟到期后可能无法再有移除者等待的情况下被实时移除。
try {
available.awaitNanos(delay);
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
// ---- 无论当前移除者是正常/异常的退出,在退出之前如果发现当前延迟工作队列还存在新头元素且[领导者]不存
// 在,则需要唤醒一个等待中的移除者,目的是令之对新头元素进行专属等待。当然,前提是存在等待中的移除者,
// 否则该操作将没有任何实际效果。
if (leader == null && queue[0] != null)
available.signal();
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 轮询
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 从当前延迟工作队列的头部移除并获取剩余延迟最小的延迟到期元素,并触发后续元素的重排序。该方法是头部移除方
* 法“阻塞”形式的实现,当当前延迟工作队列存在延迟到期元素时移除并返回头延迟到期元素;否则在指定等待时间内有
* 限等待至存在延迟到期元素为止,超出指定等待时间则返回null。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先会计算等待截止时间,随后在加锁(中断后会抛出中断异常)的情况下从[队列]中获取头元素,并判断头
* 元素是否存在,不存在则继续判断当前时间是否已超过等待截止时间,是则直接返回null,否则令当前移除者根据等待
* 截止时间进入有限等待状态,直至因为存在延迟到期元素/专属等到头元素延迟到期/超时而唤醒。
* ---- 如果头元素存在且已迟到期,是则直接调用finishPoll(RunnableScheduledFuture < ? > f)方法移除该头延迟到期元素
* 并完成对后续元素的排序后结束方法;否则等待截止时间是否已到。是则直接返回null;否则继续判断等待截止时间是
* 否小于头元素的剩余延迟时间或者当前[领导者] 是否存在。是则意味着当前移除者无法等待到头元素延迟到期或该头元
* 素已被专属等待,当前线程根据等待截止时间进入有限等待状态;否则令当前移除者对之进行专属等待,即令移除者进
* 入有限等待状态,且等待时间为头元素的剩余等待时间,以确保头元素延迟到期后当前移除者可以(接近)实时的将之
* 移除。领导者无法保证头元素一定会被自身移除,也可能被适时到来 / 唤醒的外部 / 内部线程移除。
* ---- 当前移除者如果在专属等待头元素延迟到期期间被中断则将抛出中断异常,但是在排除中断异常之,如果发现自身
* 还是[领导者],则需要将[领导者] 赋值为null表示自身退出领导者地位。因为被中断后当前线程将退出该方法,如果不
* 主动失去领导者地位,则后续的移除者将无法对头元素进行专属等待。
* ---- 这会导致头元素延迟到期后可能无法再有移除者等待的情况下被实时移除。而如果移除者是因为正常的方式被唤醒,
* 则需要计算剩余的等待截止时间,已备如果未能成功移除头元素的情况下作为重新进入等待状态直接退出方法的判断条
* 件时间。
* ---- 无论当前移除者是正常/异常的退出,在退出之前如果发现当前延迟工作队列还存在新头元素且[领导者]不存在,则
* 需要唤醒一个等待中的移除者,目的是令之对新头元素进行专属等待。当然,前提是存在等待中的移除者,否则该操作
* 将没有任何实际效果。
*/
public RunnableScheduledFuture<?> poll(long timeout, TimeUnit unit) throws InterruptedException {
// ---- 方法首先会计算等待截止时间,随后在加锁(中断后会抛出中断异常)的情况下从[队列]中获取头元素,并判断
// 头元素是否存在,不存在则继续判断当前时间是否已超过等待截止时间,是则直接返回null,否则令当前移除者根据
// 等待截止时间进入有限等待状态,直至因为存在延迟到期元素/专属等到头元素延迟到期/超时而唤醒。
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (; ; ) {
RunnableScheduledFuture<?> first = queue[0];
if (first == null) {
if (nanos <= 0)
return null;
else
nanos = available.awaitNanos(nanos);
} else {
// ---- 如果头元素存在且已迟到期,是则直接调用finishPoll(RunnableScheduledFuture < ? > f)方法移除该头
// 延迟到期元素并完成对后续元素的排序后结束方法;否则等待截止时间是否已到。是则直接返回null;否
// 则继续判断等待截止时间是否小于头元素的剩余延迟时间或者当前[领导者] 是否存在。是则意味着当前移
// 除者无法等待到头元素延迟到期或该头元素已被专属等待,当前线程根据等待截止时间进入有限等待状态;
// 否则令当前移除者对之进行专属等待,即令移除者进入有限等待状态,且等待时间为头元素的剩余等待时
// 间,以确保头元素延迟到期后当前移除者可以(接近)实时的将之移除。领导者无法保证头元素一定会被
// 自身移除,也可能被适时到来 / 唤醒的外部 / 内部线程移除。
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)
return finishPoll(first);
if (nanos <= 0)
return null;
// don't retain ref while waiting
// 不要在等待期间保留引用
first = null;
if (nanos < delay || leader != null)
nanos = available.awaitNanos(nanos);
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;
// ---- 当前移除者如果在专属等待头元素延迟到期期间被中断则将抛出中断异常,但是在排除中断异常之
// 前,如果发现自身还是[领导者],则需要将[领导者] 赋值为null表示自身退出领导者地位。因为被中断后
// 当前线程将退出该方法,如果不主动失去领导者地位,则后续的移除者将无法对头元素进行专属等待,
// ---- 这会导致头元素延迟到期后可能无法再有移除者等待的情况下被实时移除。而如果移除者是因为正常
// 的方式被唤醒,则需要计算剩余的等待截止时间,已备如果未能成功移除头元素的情况下作为重新进入等
// 待状态直接退出方法的判断条件时间。
try {
long timeLeft = available.awaitNanos(delay);
nanos -= delay - timeLeft;
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
// ---- 无论当前移除者是正常/异常的退出,在退出之前如果发现当前延迟工作队列还存在新头元素且[领导者]不存
// 在,则需要唤醒一个等待中的移除者,目的是令之对新头元素进行专属等待。当然,前提是存在等待中的移除者,
// 否则该操作将没有任何实际效果。
if (leader == null && queue[0] != null)
available.signal();
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 清理
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 从当前延迟工作队列中移除所有元素。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会遍历[队列],将每个数组槽赋值为null,并将每个元素的[堆索引]都设置为-1,表示其已从当前延迟工作队列
* 中移除。并将[大小]赋值为0,表示所有的元素都已被移除。
*/
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
for (int i = 0; i < size; i++) {
RunnableScheduledFuture<?> t = queue[i];
if (t != null) {
queue[i] = null;
setIndex(t, -1);
}
}
size = 0;
} finally {
lock.unlock();
}
}
/**
* Returns first element only if it is expired. Used only by drainTo. Call only when holding lock.
* 如果只是已到期则返回首个元素。在通过drainTo方法调用,只在持有锁期间调用。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 窥视过期
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 从当前延迟工作队列的头部获取延迟到期元素
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先会从[队列]中获取头元素,随后判断头元素是否存在且是否延迟到期,是则返回头延迟到期元素;否则返
* 回null。
*/
private RunnableScheduledFuture<?> peekExpired() {
// assert lock.isHeldByCurrentThread();
// 断言:锁被当前线程持有。
// ---- 方法首先会从[队列]中获取头元素,随后判断头元素是否存在且是否延迟到期,是则返回头延迟到期元素;否则
// 返回null。
RunnableScheduledFuture<?> first = queue[0];
return (first == null || first.getDelay(NANOSECONDS) > 0) ? null : first;
}
/**
* Returns first element only if it is expired. Used only by drainTo. Call only when holding lock.
* 如果只是已到期则返回首个元素。在通过drainTo方法调用,只在持有锁期间调用。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 流失
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 将当前延迟工作队列中的所有延迟到期元素流失到指定集中,并返回流失的延迟到期元素总数。被流失的延迟到期元素
* 将不再存在于当前延迟工作队列中。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先判断指定集是否为null,是则抛出空指针异常;否则继续判断指定集是否为当前延迟工作队列,是则抛出
* 非法参数异常。
* ---- 随后在锁的保护下,方法会循环地获取头元素。如果头元素不为null且延迟到期,则将该头元素加入到指定集中,
* 再通过finishPoll(RunnableScheduledFuture<?> f)方法将头元素从[队列]中移除并完成对后续元素的排序。之所以按"获取
* —> 添加 —> 移除"的顺序操作而不是按"移除 —> 添加"的顺序操作是为了避免元素在被移除后添加至指定集的过程中因
* 为各原因(通常是因为达到容量上限)而新增失败导致丢失(即不存在与任何集中)的情况发生。最后递增已流失元素
* 的数量,直至最终所有元素流失结束后返回。
*/
public int drainTo(Collection<? super Runnable> c) {
// ---- 方法首先判断指定集是否为null,是则抛出空指针异常;否则继续判断指定集是否为当前延迟工作队列,是则抛
// 出非法参数异常。
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
// ---- 随后在锁的保护下,方法会循环地获取头元素。如果头元素不为null且延迟到期,则将该头元素加入到指定集中,
// 再通过finishPoll(RunnableScheduledFuture<?> f)方法将头元素从[队列]中移除并完成对后续元素的排序。之所以按"
// 获取 —> 添加 —> 移除"的顺序操作而不是按"移除 —> 添加"的顺序操作是为了避免元素在被移除后添加至指定集的
// 过程中因为各原因(通常是因为达到容量上限)而新增失败导致丢失(即不存在与任何集中)的情况发生。最后递增
// 已流失元素的数量,直至最终所有元素流失结束后返回。
final ReentrantLock lock = this.lock;
lock.lock();
try {
RunnableScheduledFuture<?> first;
int n = 0;
while ((first = peekExpired()) != null) {
// In this order, in case add() throws.
// 按这个顺序,以防add()抛出。
c.add(first);
finishPoll(first);
++n;
}
return n;
} finally {
lock.unlock();
}
}
/**
* Returns first element only if it is expired. Used only by drainTo. Call only when holding lock.
* 如果只是已到期则返回首个元素。在通过drainTo方法调用,只在持有锁期间调用。
*
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 流失
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 将当前延迟工作队列中最多指定数量的延迟到期元素流失到指定集中,并返回流失的延迟到期元素总数。被流失的延迟
* 到期元素将不再存在于当前延迟工作队列中。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法首先判断指定集是否为null,是则抛出空指针异常;否则继续判断指定集是否为当前延迟工作队列,是则抛出
* 非法参数异常。
* ---- 随后在锁的保护下,方法会在不超过指定最大元素总数的前提下循环地获取头元素。如果头元素不为null且延迟到
* 期,则将该头元素加入到指定集中,再通过finishPoll(RunnableScheduledFuture<?> f)方法将头元素从[队列]中移除并完
* 成对后续元素的排序。之所以按"获取 —> 添加 —> 移除"的顺序操作而不是按"移除 —> 添加"的顺序操作是为了避免元
* 素在被移除后添加至指定集的过程中因为各原因(通常是因为达到容量上限)而新增失败导致丢失(即不存在与任何集
* 中)的情况发生。最后递增已流失元素的数量,直至最终所有元素流失或流失的元素总数已达指定最大元素数量后返回。
*/
public int drainTo(Collection<? super Runnable> c, int maxElements) {
// ---- 方法首先判断指定集是否为null,是则抛出空指针异常;否则继续判断指定集是否为当前延迟工作队列,是则抛
// 出非法参数异常;否则再判断指定最大元素数量是否 <= 0,是则直接返回0,因为方法无需流失任何元素。
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
return 0;
// ---- 随后在锁的保护下,方法会在不超过指定最大元素总数的前提下循环地获取头元素。如果头元素不为null且延迟
// 到期,则将该头元素加入到指定集中,再通过finishPoll(RunnableScheduledFuture<?> f)方法将头元素从[队列]中移除
// 并完成对后续元素的排序。之所以按"获取 —> 添加 —> 移除"的顺序操作而不是按"移除 —> 添加"的顺序操作是为了
// 避免元素在被移除后添加至指定集的过程中因为各原因(通常是因为达到容量上限)而新增失败导致丢失(即不存在
// 与任何集中)的情况发生。最后递增已流失元素的数量,直至最终所有元素流失或流失的元素总数已达指定最大元素
// 数量后返回。
final ReentrantLock lock = this.lock;
lock.lock();
try {
RunnableScheduledFuture<?> first;
int n = 0;
while (n < maxElements && (first = peekExpired()) != null) {
// In this order, in case add() throws.
// 按这个顺序,以防add()抛出。
c.add(first);
finishPoll(first);
++n;
}
return n;
} finally {
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 转化数组
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 获取按迭代器顺序包含当前延迟工作队列中所有元素的新数组。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会在锁的保护下直接通过Arrays.copyOf(U[] original, int newLength, Class<? extends T[]> newType)方法创建
* 数组并完成对元素的复制。
*/
public Object[] toArray() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return Arrays.copyOf(queue, size, Object[].class);
} finally {
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 转化数组
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 获取按迭代器顺序包含当前延迟队列中所有元素的泛型数组。如果参数泛型数组长度足以容纳所有元素,则令之承载所
* 有元素后返回。并且如果参数泛型数组的长度大于当前延迟队列的元素总数,则将已承载所有元素的参数泛型数组的
* size索引位置设置为null,表示从当前延迟队列中承载的元素到此为止。当然,该方案只对不允许保存null元素的集有效。
* 如果参数泛型数组的长度不足以承载所有元素,则重分配一个相同泛型且长度与当前延迟队列元素总数相同的新泛型数
* 组以承载所有元素后返回。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法会锁的保护下首先判断指定数组是否足以容纳当前延迟工作队列中所有的元素,否通过
* Arrays.copyOf(U[] original, int newLength, Class<? extends T[]> newType)方法创建数组并完成对元素的复制;是则通
* 过System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)方法将元素复制到指定集上,并将
* size索引位置复制为null表示元素到此为止。
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
// ---- 方法会锁的保护下首先判断指定数组是否足以容纳当前延迟工作队列中所有的元素,否通过
// Arrays.copyOf(U[] original, int newLength, Class<? extends T[]> newType)方法创建数组并完成对元素的复制;是
// 则通过System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)方法将元素复制到指定集上,
// 并将size索引位置复制为null表示元素到此为止。
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (a.length < size)
return (T[]) Arrays.copyOf(queue, size, a.getClass());
System.arraycopy(queue, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
} finally {
lock.unlock();
}
}
/**
* @Description: ----------------------------------------------------------- 名称 -----------------------------------------------------------
* 迭代器
* @Description: ----------------------------------------------------------- 作用 -----------------------------------------------------------
* 创建可遍历当前延迟工作队列中元素的迭代器。
* @Description: ----------------------------------------------------------- 逻辑 -----------------------------------------------------------
* ---- 方法直接基于[队列]数组快照创建迭代器实现。
*/
public Iterator<Runnable> iterator() {
return new Itr(Arrays.copyOf(queue, size));
}
/**
* Snapshot iterator that works off copy of underlying q array.
* 基于底层q数组副本的快照迭代器。
*/
private class Itr implements Iterator<Runnable> {
/**
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 数组
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* 持有元素数组
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
* ----
*/
final RunnableScheduledFuture<?>[] array;
/**
* index of next element to return
* 用于返回下个元素的索引
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 游标
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* 记录下个迭代元素的索引
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
* ----
*/
int cursor = 0;
/**
* index of last element, or -1 if no such
* 上个元素的索引,如果没有则为-1
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 上个返回
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* 记录上个返回元素的索引
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
* ----
*/
int lastRet = -1;
/**
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 迭代器
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* 创建指定元素数组的迭代器
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
* ----
*/
Itr(RunnableScheduledFuture<?>[] array) {
this.array = array;
}
/**
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 有下个
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* 判断当前迭代器是否存在下个迭代元素,是则返回true;否则返回false。
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
* ---- 方法通过判断[游标]是否小于[数组]的长度实现,是则说明存在,返回true;否则说明不存在,返回false。
*/
public boolean hasNext() {
return cursor < array.length;
}
/**
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 下个
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* 获取当前迭代器的下个迭代元素
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
* ---- 方法首先会判断[游标]是否>= [数组]的长度,是则说明无下个可迭代元素,直接抛出无如此元素异常。随后将[上
* 个返回]赋值为游标,因此下个迭代元素返回后[游标]中记录的索引将成为上个元素的索引。最后通过[游标]获取下个
* 迭代元素并返回,并递增[游标]以定个新的下个迭代元素。
*/
public Runnable next() {
if (cursor >= array.length)
throw new NoSuchElementException();
lastRet = cursor;
return array[cursor++];
}
/**
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 移除
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* 将上个迭代元素从当前迭代器中移除
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
* ---- 方法首先会判断[上个返回]是否 < 0,是则说明当前迭代器尚未迭代或上个迭代元素已被移除,抛出非法状态异
* 常;否则调用当前延迟工作队列的remove(Object x)方法上个迭代元素,并将[上个返回]设置为-1,表示已移除。
*/
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
DelayedWorkQueue.this.remove(array[lastRet]);
lastRet = -1;
}
}
}
}