java多线程 ScheduledThreadPoolExecutor源码分析

目录

简介

4个字段,方法now,内部类ScheduledTutureTask

方法canRunInCurrentRunState,delayedExecute,reExecutePeriodic,onShutdown,2个decorateTask,4个构造函数

方法2个triggerTime,overflowFree,4个scheduleXXX,execute,3个submit

方法3个setXXX/getXXX,shutdown,shutdownNow,getQueue

内部类DelayedWorkQueue


简介

package java.util.concurrent;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.*;

/**
 * 一个ThreadPoolExecutor,它可以额外调度命令在给定的延迟后运行,或定期执行。
 * 当需要多个工作线程时,或者当需要ThreadPoolExecutor(这个类的扩展)的额外灵活性或功能时,这个类比java.util. Timer更可取。
 *
 * <p>延迟任务的执行不会早于它们被启用的时间,但是对于它们被启用后何时开始执行没有任何实时的保证。
 * 计划完全相同执行时间的任务以先进先出(FIFO)的提交顺序启用。
 *
 * <p>当提交的任务在运行之前被取消时,执行将被抑制。
 * 默认情况下,这样一个被取消的任务不会自动从工作队列中删除,直到它的延迟时间结束。
 * 虽然这可以进行进一步的检查和监视,但它也可能导致取消任务的无限保留。
 * 为了避免这种情况,将setRemoveOnCancelPolicy设置为true,这将导致任务在取消时立即从工作队列中删除。
 *
 * <p>通过scheduleAtFixedRate或scheduleWithFixedDelay调度的任务的连续执行不会重叠。
 * 虽然不同的执行可能由不同的线程执行,但前一次执行的效果发生在后续执行的效果之前。
 *
 * <p>虽然这个类继承自ThreadPoolExecutor,但继承的一些调优方法对它没有用处。
 * 特别是,因为它使用corePoolSize线程和无界队列作为固定大小的池,所以调整maximumPoolSize没有任何有用的效果。
 * 此外,将corePoolSize设置为0或使用allowCoreThreadTimeOut几乎从来不是一个好主意,
 * 因为这可能会使线程池没有线程来处理任务,一旦他们成为合格的运行者。
 *
 * <p>扩展注释:
 * 这个类重写execute和submit方法来生成内部ScheduledFuture对象来控制每个任务的延迟和调度。
 * 为了保留功能,子类中对这些方法的任何进一步覆盖都必须调用超类版本,这有效地禁用了额外的任务定制。
 * 但是,这个类提供了另一个受保护的扩展方法decorateTask (Runnable和Callable各有一个版本),可以用来定制具体的任务类型,
 * 用于执行通过execute、submit、schedule、scheduleAtFixedRate和scheduleWithFixedDelay输入的命令。
 * 默认情况下,ScheduledThreadPoolExecutor使用扩展FutureTask的任务类型。但是,可以使用子类的形式来修改或替换:
 *
 *  <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>
 *
 * ThreadPoolExecutor的功能已经很强大了,但却没有延时任务的功能。
 * 对于ScheduledThreadPoolExecutor,它的父类ThreadPoolExecutor所做的提交任务都是延时时间为0的延时任务。
 * 同时,它也提供了执行周期任务的功能。
 * 
 * 从类定义可知,ScheduledThreadPoolExecutor继承了ThreadPoolExecutor,
 * 实际上它也是复用了ThreadPoolExecutor的大部分逻辑,只是加了自己的特化处理。
 * 
 * 有两种周期任务:FixedRate和FixedDelay。
 * 下一个周期的重复任务能够进入队列的前提是,当前周期执行重复任务时没有抛出异常。
 * FixedRate是当前周期的    开始时刻    与下一个周期的开始时刻总是相差period单位时间。但如果当前周期执行花费太多时间,会导致下一个周期迟迟无法入队。
 * FixedDelay是当前周期的    结束时刻    与下一个周期的开始时刻总是相差period单位时间。当前周期的执行时间有多久都不影响。
 * 任务入队后,即将当前时刻已经可以被执行,如果没有空闲的工作线程来取task,那么也不会被执行。因为ScheduledThreadPoolExecutor最多只能起corePoolSize个线程。
 * 关于shutdown的逻辑有点不一样,它是根据两个run-after-shutdown参数来判断队列剩余任务在shutdown后是否可以继续被执行。
 * @since 1.5
 * @author Doug Lea
 */
public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService 

4个字段,方法now,内部类ScheduledTutureTask


    /*
     * 这个类专门用于ThreadPoolExecutor的实现
     *
     * 1. 使用自定义任务类型,ScheduledFutureTask的任务,甚至那些不需要调度的任务
     *    (即,那些使用ExecutorService执行而不是ScheduledExecutorService方法提交的任务),这些任务被视为延迟为0的任务。
     *
     * 2. 使用自定义队列(DelayedWorkQueue),无界DelayQueue的变体。
     *    与ThreadPoolExecutor相比,缺乏容量约束以及corePoolSize和maximumPoolSize实际上是相同的这一事实,简化了某些执行机制(参见delayedExecute)。
     *
     * 3. 支持可选的run-after-shutdown参数,这将导致覆盖shutdown方法来删除和取消关机后不应该运行的任务,
     *    以及当任务(重新)提交与shutdown重叠时不同的重新检查逻辑。
     *
     * 4. 任务装饰方法允许拦截和插装,这是必需的,因为子类不能重写提交方法来获得这种效果。
     *    但是这些对池控制逻辑没有任何影响。
     */

    /**
     * 如果在关机时取消/抑制定期任务,则为False。
     * 线程池状态变成Shutdown后,是否还需要执行队列中的周期任务
     */
    private volatile boolean continueExistingPeriodicTasksAfterShutdown;

    /**
     * 如果在关机时取消非周期性任务,则为False。
     * 线程池状态变成Shutdown后,是否还需要执行队列中的延迟任务。默认为true
     */
    private volatile boolean executeExistingDelayedTasksAfterShutdown = true;

    /**
     * 如果ScheduledFutureTask.Cancel应该从队列中删除,则为true
     * 取消Future后,是否将其从队列中移除
     */
    private volatile boolean removeOnCancel = false;

    /**
     * 序号打破调度关系,并反过来保证在捆绑条目之间的先进先出顺序。
     * 如果两个任务的到期时间相同,则通过这个比较前后
     */
    private static final AtomicLong sequencer = new AtomicLong();

    /**
     * 返回当前纳秒时间。
     */
    final long now() {
        return System.nanoTime();
    }

    // ScheduledFutureTask实例在delayedExecute中入队到task队列中,所以工作线程出队task后执行的是ScheduledFutureTask#run()。
    // 这个类图看起来很吓人,其实我们只需要关注它同时实现了Runnable Future Delayed接口即可,
    // 当然,ScheduledFutureTask的逻辑大量复用了其父类FutureTask的逻辑。
    private class ScheduledFutureTask<V>
            extends FutureTask<V> implements RunnableScheduledFuture<V> {

        /** 打破FIFO顺序编号 通过原子类获得的独一无二的序号,当两个task的time相同时,用这个属性来决定先后*/
        private final long sequenceNumber;

        /** 以nanoTime为单位启用任务执行的时间  一个绝对时间,从这个时间往后,当前task可以被执行*/
        private long time;

        /**
         * 周期值。
         * 1. 正数代表是fixed-rate周期任务。
         * 2. 负数代表是fixed-delay周期任务。
         * 3. 0代表是延时任务。
         */
        private final long period;

        /** 下一个周期将要被执行的task,默认是this  */
        RunnableScheduledFuture<V> outerTask = this;

        /**
         * task在堆上的索引,标识作用,当被从堆中删除时,索引为-1,正常为非负数。用来判断是否需要remove
         */
        int heapIndex;

        /**
         * 使用给定的基于nanotime的触发器时间创建一次性操作。
         */
        ScheduledFutureTask(Runnable r, V result, long ns) {
            super(r, result);
            this.time = ns;
            this.period = 0;
            this.sequenceNumber = sequencer.getAndIncrement();
        }

        /**
         * 使用给定的纳米时间和周期创建一个周期操作。
         */
        ScheduledFutureTask(Runnable r, V result, long ns, long period) {
            super(r, result);
            this.time = ns;
            this.period = period;
            this.sequenceNumber = sequencer.getAndIncrement();
        }

        /**
         * 使用给定的基于nanotime的触发器时间创建一次性操作。
         */
        ScheduledFutureTask(Callable<V> callable, long ns) {
            super(callable);
            this.time = ns;
            this.period = 0;
            this.sequenceNumber = sequencer.getAndIncrement();
        }

        public long getDelay(TimeUnit unit) {
            return unit.convert(time - now(), NANOSECONDS);
        }

        public int compareTo(Delayed other) {
            if (other == this) // compare zero if same object
                return 0;
            if (other instanceof ScheduledFutureTask) {
                ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
                long diff = time - x.time;
                if (diff < 0)
                    return -1;
                else if (diff > 0)
                    return 1;
                else if (sequenceNumber < x.sequenceNumber)
                    return -1;
                else
                    return 1;
            }
            long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
            return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
        }

        /**
         * 如果这是一个周期操作(而不是一次性操作)返回true。
         *
         * @return {@code true} if periodic
         */
        public boolean isPeriodic() {
            return period != 0;
        }

        /**
         * 设置周期性任务的下一次运行时间。
         */
        private void setNextRunTime() {
            long p = period;
            if (p > 0)  //固定速率执行,scheduleAtFixedRate
                time += p;  //按照上一次周期的开始时刻,再加上周期值
            else       //固定延迟执行,scheduleWithFixedDelay
                time = triggerTime(-p);   //按照现在时刻(即当前周期的结束时刻),再加上周期值
        }


      //ScheduledFutureTask内部类
        public boolean cancel(boolean mayInterruptIfRunning) {
        	// super.cancel(mayInterruptIfRunning)这里是直接调用到ScheduledFutureTask的父类FutureTask的实现。
        	// 而出队成功则说明这个task肯定没有被工作线程执行过task.run(),所以上面的super.cancel(mayInterruptIfRunning)
        	// 肯定会使得FutureTask的状态变成CANCELLED或INTERRUPTED。
        	
        	// 即使取消成功,还需要判断&& removeOnCancel && heapIndex >= 0,removeOnCancel代表取消后是否需要删除,
        	// 而heapIndex则是task在最小堆中的索引,如果它存在于堆中那么索引是>= 0的。
        	
        	// remove(this)看起来有点重复操作,这其实因为ScheduledFutureTask#cancel会在ScheduledFutureTask#run中调用。
        	// 考虑本章的执行过程,这里会heapIndex不满足而不会执行remove(this)。
            boolean cancelled = super.cancel(mayInterruptIfRunning);//直接调用到父类FutureTask的实现
            if (cancelled && removeOnCancel && heapIndex >= 0)
                remove(this);//调用到外部类的方法,也就是上面的方法
            return cancelled;
        }


        /**
         * 重写FutureTask版本,以便在周期性时重置/requeue。
         * 
         * 上面说过,scheduleAtFixedRate在一定条件下,当前周期的开始时刻与下一个周期的开始时刻总是相差period单位时间。
         * 虽然setNextRunTime确实能保证,两个周期的开始时刻总是相差period,
         * 但加入队列的时机是ScheduledFutureTask.super.runAndReset()完成后,如果task执行时间需要很久已经超过了period,
         * 那么下一个周期的实际开始时刻的差距则肯定超过了period了,即这种情况下,下一个周期的任务加入队列时,就已经是可以被执行的状态了。
         * 
         * 而scheduleWithFixedDelay的逻辑,则完全符合ScheduledFutureTask.super.runAndReset()的完成时机,
         * runAndReset执行完后setNextRunTime会以当前时刻(当前周期的结束时刻)再加上period作为新任务的time。
         * 而在reExecutePeriodic执行后,即使这个task马上就能被执行,如果没有空闲的工作线程,那么这个task也得等到有空闲线程时,才会被执行。
         */
        public void run() {
            boolean periodic = isPeriodic();
            if (!canRunInCurrentRunState(periodic))//根据当前线程池状态,是否可以运行
                cancel(false);//取消task,并根据removeOnCancel移除task
            //如果可以运行
            else if (!periodic)//如果不是周期任务,那就执行父类run
                ScheduledFutureTask.super.run();
            //如果是周期任务,那就执行父类的runAndReset。
            // 相比run函数,这个函数有些不同:
            
            // 正常执行完c.call()后,不会去执行set()。因为本来c.call()就没有返回值。
            // runAndReset具有返回值,ran && s == NEW前者代表c.call()没有抛出异常
            //(如果执行了setException,状态也会经历NEW -> COMPLETING -> EXCEPTIONAL的),
            // 后者代表没有被执行过task.cancel()(可能经历NEW -> CANCELLED或NEW -> INTERRUPTING -> INTERRUPTED)。
            // 总之,没有出现上面的异常情况的话,task状态会一直保持NEW的。
            // 如果ScheduledFutureTask.super.runAndReset()没有发现异常情况,并顺利返回true的话,那么就把下一个周期的重复task入队:
            
            else if (ScheduledFutureTask.super.runAndReset()) {//返回true才会把下一个重复task放入队列
                setNextRunTime();
                // reExecutePeriodic将重复task入队,整个过程和delayedExecute类似。
                reExecutePeriodic(outerTask);
            }
        }
    }


方法canRunInCurrentRunState,delayedExecute,reExecutePeriodic,onShutdown,2个decorateTask,4个构造函数


    /**
     * 如果可以运行给定当前运行状态和运行后关闭参数的任务,则返回true。
     * 
     *
     * @param periodic true if this task periodic, false if delayed
     */
    boolean canRunInCurrentRunState(boolean periodic) {
    	// 如果是RUNNING状态,那肯定可以执行阿。返回true。
    	// 如果是SHUTDOWN状态,则根据传入参数决定。返回shutdownOK的值。
    	// 如果是SHUTDOWN之后的值(STOP、TIDYING、TERMINATED),那肯定不可以执行。返回false。
    	// 总之,canRunInCurrentRunState返回false,就代表刚入队的task不能被执行。
        return isRunningOrShutdown(periodic ?
                                   continueExistingPeriodicTasksAfterShutdown :
                                   executeExistingDelayedTasksAfterShutdown);
    }

    /**
     * 延迟或周期性任务的主要执行方法。如果池关闭,拒绝任务。
     * 否则,将任务添加到队列中,并在必要时启动一个线程来运行它。
     * (我们不能预先启动线程来运行该任务,因为该任务(可能)还不应该运行。)
     * 如果在添加任务时池已关闭,则根据状态和关机后运行参数的要求取消并删除它。
     * 
     * 所有提交任务的函数都调用到了delayedExecute,它才是提交任务的关键逻辑。
     *
     * @param task the task
     */
    private void delayedExecute(RunnableScheduledFuture<?> task) {
        if (isShutdown())//如果线程池已经关闭,那么不能提交新任务
            reject(task);//执行拒绝策略
        else {
            super.getQueue().add(task);//先添加到队列
            // 再看看加入队列后发现池关闭的逻辑,先执行canRunInCurrentRunState(task.isPeriodic()):
            // 既然canRunInCurrentRunState返回了false,则需要从队列移除task:
            // 既然已经移除成功,那么这个task则肯定不会执行到了,但提交任务函数总会返回这个ScheduledFuture对象的,
            // 所以我们必须告诉调用者这个信息(线程池已经关闭),通过调用task.cancel(false)。
            
            if (isShutdown() &&//添加后发现线程池关闭
                !canRunInCurrentRunState(task.isPeriodic()) &&//判断该任务在shutdown后,是否还可以执行
                remove(task))//上面判断不能执行,那么remove这个task
                task.cancel(false);//取消这个task
            
            else
            	// 我们先看正常逻辑,不管线程池关闭的情况,那么加入task队列后,执行ensurePrestart。
            	// 可以发现ScheduledThreadPoolExecutor的提交任务的策略很简单:
            	// 先把task入队队列。
            	// 增加一个线程,直到线程数量达到corePoolSize。
                ensurePrestart();//启动新线程,去获得task来执行
        }
    }


    /**
     * 除非当前运行状态不允许,否则将周期性任务重新队列。
     * 与delayedExecute的想法相同,只不过是丢弃任务而不是拒绝。
     *
     * @param task the task
     */
    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
        if (canRunInCurrentRunState(true)) {//判断当前线程池状态,是否可以入队
            super.getQueue().add(task);//任务入列
            //如果入队后发现线程池状态变了,则先移除task,再取消它。这和提交任务的逻辑一样
            if (!canRunInCurrentRunState(true) && remove(task))
                task.cancel(false);
            else
                ensurePrestart();//启动一个新的线程等待任务
        }
    }


    /**
     * 取消并清除由于关机策略而不应运行的所有任务的队列。在super.shutdown调用。
     */
    @Override void onShutdown() {
    	// 这使得ScheduledThreadPoolExecutor的shutdown的逻辑完全不一样了,因为线程池shutdown后,
    	// 剩余任务不再是肯定会执行到的了,而是根据两个run-after-shutdown参数
    	//(continueExistingPeriodicTasksAfterShutdown和executeExistingDelayedTasksAfterShutdown)来做决定。
        BlockingQueue<Runnable> q = super.getQueue();
        boolean keepDelayed =
            getExecuteExistingDelayedTasksAfterShutdownPolicy();
        boolean keepPeriodic =
            getContinueExistingPeriodicTasksAfterShutdownPolicy();
        if (!keepDelayed && !keepPeriodic) {//如果延时任务和周期任务都不允许在Shutdown后被执行,那好办,无差别取消每个任务
            for (Object e : q.toArray())
                if (e instanceof RunnableScheduledFuture<?>)
                    ((RunnableScheduledFuture<?>) e).cancel(false);
            q.clear();
        }
        else {
            // 遍历队列的快照,避免迭代器异常
            for (Object e : q.toArray()) {
                if (e instanceof RunnableScheduledFuture) {
                    RunnableScheduledFuture<?> t =
                        (RunnableScheduledFuture<?>)e;
                    if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) || //根据延时任务还是周期任务
                        t.isCancelled()) { // 即使task已经取消掉了,也要移除它
                        if (q.remove(t))
                            t.cancel(false);
                    }
                }
            }
        }
        tryTerminate();//帮助终止线程池
    }


    /**
     * 修改或替换用于执行runnable的任务。
     * 此方法可用于覆盖用于管理内部任务的具体类。默认实现只是返回给定的任务。
     *
     * @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
     * @since 1.6
     */
    protected <V> RunnableScheduledFuture<V> decorateTask(
        Runnable runnable, RunnableScheduledFuture<V> task) {
        return 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
     * @since 1.6
     */
    protected <V> RunnableScheduledFuture<V> decorateTask(
        Callable<V> callable, RunnableScheduledFuture<V> task) {
        return task;
    }

    /**
     * 使用给定的核心池大小创建一个新的ScheduledThreadPoolExecutor。
     *
     * @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}
     */
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

    /**
     * 使用给定的初始参数创建一个新的ScheduledThreadPoolExecutor。
     *
     * @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}
     * @throws NullPointerException if {@code threadFactory} is null
     */
    public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }

    /**
     * 使用给定的初始参数创建一个新的ScheduledThreadPoolExecutor。
     *
     * @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}
     * @throws NullPointerException if {@code handler} is null
     */
    public ScheduledThreadPoolExecutor(int corePoolSize,
                                       RejectedExecutionHandler handler) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), handler);
    }

    /**
     * 使用给定的初始参数创建一个新的ScheduledThreadPoolExecutor。
     * 
     * 在上一篇文章中我们知道execute中的执行策略受到这三个成员:
     * corePoolSize、maximumPoolSize、阻塞队列 的影响。
     * 但从这个构造器中可以发现maximumPoolSize和阻塞队列都已经被写死了。
     * 
     * 并且由于重写了execute,现在ScheduledThreadPoolExecutor的执行策略是:
     * 先让线程数量增加到corePoolSize,之后不会再增加。
     *
     * @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}
     * @throws NullPointerException if {@code threadFactory} or
     *         {@code handler} is null
     */
    public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory,
                                       RejectedExecutionHandler handler) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory, handler);
    }


方法2个triggerTime,overflowFree,4个scheduleXXX,execute,3个submit


    /**
     * 返回延迟操作的触发时间。
     */
    private long triggerTime(long delay, TimeUnit unit) {
        return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
    }

    /**
     * 返回延迟操作的触发时间。
     */
    long triggerTime(long delay) {
        return now() +
            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
    }

    /**
     * 将队列中所有延迟的值约束为Long.MAX_VALUE,以避免在compareTo中溢出。
     * 如果一个任务有资格被退出队列,但还没有,而另一个任务被添加,延迟+long . max_value,则可能发生这种情况。
     */
    private long overflowFree(long delay) {
        Delayed head = (Delayed) super.getQueue().peek();
        if (head != null) {
            long headDelay = head.getDelay(NANOSECONDS);
            if (headDelay < 0 && (delay - headDelay < 0))
                delay = Long.MAX_VALUE + headDelay;
        }
        return delay;
    }

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        // command, null会用适配器合成一个Callable出来。
        // triggerTime(delay, unit)得出任务可以执行的绝对时间。
        // decorateTask的默认实现是直接返回第二个参数,我们知道第二个实参也是经过第一个实参才构造出来的。
        // 所以我们可以自己重写decorateTask,忽略掉第二个参数,然后通过第一个参数构造出一个自定义实现的RunnableScheduledFuture。
        RunnableScheduledFuture<?> t = decorateTask(command,
            new ScheduledFutureTask<Void>(command, null,
                                          triggerTime(delay, unit)));
        delayedExecute(t);
        return t;
    }

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay,
                                           TimeUnit unit) {
        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}
     */
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit) {
    	// 在一定条件下,这个函数的周期任务,当前周期的    开始时刻    与下一个周期的开始时刻总是相差period单位时间。
    	// 多了一个参数unit.toNanos(period)设置周期,为正数代表是FixedRate。
    	// 由于decorateTask默认实现返回第二个实参本身,且ScheduledFutureTask的outerTask成员默认初始化为this,所以这里的sft.outerTask = t实际上没有作用。
    	// 由于decorateTask的实现可能会被修改,所以delayedExecute(t)的实参一定要是decorateTask的返回值。
    	// 这个函数的周期任务,当前周期的    结束时刻    与下一个周期的开始时刻总是相差period单位时间。即这个函数是考虑了每个周期的执行时间了的。
        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}
     */
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit) {
    	// 多了一个参数unit.toNanos(period)设置周期,为负数代表是FixedDelay。
        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;
    }

    /**
     * 执行命令不需要延迟。这相当于schedule(command, 0, anyUnit)。
     * 注意,对shutdownNow返回的队列和列表的检查将访问零延迟的ScheduledFuture,而不是command本身。
     *
     * <p>使用ScheduledFuture对象的一个后果是,调用afterExecute时总是带有一个knull秒的Throwable参数,即使命令突然终止。
     * 相反,这样一个任务的抛出的Throwable可以通过Future.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}
     */
    public void execute(Runnable command) {
    	// execute就相当于执行一个延时0秒的延时任务。
        schedule(command, 0, NANOSECONDS);
    }

    // 覆盖AbstractExecutorService方法

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public Future<?> submit(Runnable task) {
    	// 相比上一个,返回了schedule的返回值。
        return schedule(task, 0, NANOSECONDS);
    }

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public <T> Future<T> submit(Runnable task, T result) {
    	// Executors.callable(task, result)适配成一个Callable。
        return schedule(Executors.callable(task, result), 0, NANOSECONDS);
    }

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public <T> Future<T> submit(Callable<T> task) {
        return schedule(task, 0, NANOSECONDS);
    }


方法3个setXXX/getXXX,shutdown,shutdownNow,getQueue


    /**
     * 设置是否继续执行现有的定期任务的策略,即使这个执行程序已经关闭。
     * 在这种情况下,这些任务只会在shutdownNow时终止,或者在已经关闭时将策略设置为false后才终止。
     * 该值默认为false。
     *
     * @param value if {@code true}, continue after shutdown, else don't
     * @see #getContinueExistingPeriodicTasksAfterShutdownPolicy
     */
    public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) {
        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}.
     *
     * @return {@code true} if will continue after shutdown
     * @see #setContinueExistingPeriodicTasksAfterShutdownPolicy
     */
    public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() {
        return continueExistingPeriodicTasksAfterShutdown;
    }

    /**
     * 设置是否执行现有的延时任务的策略,即使此执行程序已关闭。
     * 在这种情况下,这些任务只会在shutdownNow时终止,或者在已经关闭时将策略设置为false后终止。该值默认为true。
     *
     * @param value if {@code true}, execute after shutdown, else don't
     * @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}.
     *
     * @return {@code true} if will execute after shutdown
     * @see #setExecuteExistingDelayedTasksAfterShutdownPolicy
     */
    public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() {
        return executeExistingDelayedTasksAfterShutdown;
    }

    /**
     * 设置取消任务在取消时是否应立即从工作队列中删除的策略。该值默认为false。
     *
     * @param value if {@code true}, remove on cancellation, else don't
     * @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}.
     *
     * @return {@code true} if cancelled tasks are immediately removed
     *         from the queue
     * @see #setRemoveOnCancelPolicy
     * @since 1.7
     */
    public boolean getRemoveOnCancelPolicy() {
        return removeOnCancel;
    }

    /**
     * 启动一个有序的关闭,在此关闭中执行先前提交的任务,但不接受新的任务。
     * 如果已经关闭,则调用没有额外的效果。
     *
     * <p>此方法不等待以前提交的任务完成执行。使用awaitTermination来做这个。
     *
     * <p>如果ExecuteExistingDelayedTasksAfterShutdownPolicy被设置为false,则现有的延迟未经过的任务将被取消。
     * 并且除非ContinueExistingPeriodicTasksAfterShutdownPolicy被设置为true,否则将取消现有的定时任务的未来执行。
     *
     * @throws SecurityException {@inheritDoc}
     */
    public void shutdown() {
    	// 内部有 有一个钩子方法,ScheduledThreadPoolExecutor把onShutdown实现了
        super.shutdown();
    }

    /**
     * 尝试停止所有正在积极执行的任务,停止等待任务的处理,并返回一个正在等待执行的任务列表。
     *
     * <p>此方法不等待主动执行的任务终止。使用awaitTermination来完成。
     *
     * <p>除了尽最大努力停止积极执行任务的处理之外,没有任何保证。
     * 该实现通过Thread.interrupt取消任务,因此任何未能响应中断的任务可能永远不会终止。
     *
     * @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}.
     * @throws SecurityException {@inheritDoc}
     */
    public List<Runnable> shutdownNow() {
        return super.shutdownNow();
    }

    /**
     * 返回此执行程序使用的任务队列。这个队列的每个元素都是一个ScheduledFuture,
     * 包括那些使用execute提交的任务,它们是用于调度目的的,用作零延迟ScheduledFuture的基础。
     * 这个队列上的迭代不能保证按照任务执行的顺序遍历任务。
     *
     * @return the task queue
     */
    public BlockingQueue<Runnable> getQueue() {
        return super.getQueue();
    }


内部类DelayedWorkQueue


    /**
     * 专门的延迟队列。为了与TPE声明相匹配,
     * 这个类必须被声明为BlockingQueue,即使它只能保存RunnableScheduledFutures。
     * 
     * 内部类DelayedWorkQueue实现了一个延时优先队列,它完全类似于DelayQueue,所以本文不会讲解这部分内容。
     * 唯一一点不同是,它会节点所在数组索引记录在ScheduledFutureTask节点的heapIndex成员上,它会时刻保持节点的数组索引正确。
     * 节点在堆中时,索引为非负数;节点被删除时,索引为-1。
     * 堆中查找节点时,时间复杂度为O ( 1 )。
     */
    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.)
         *
         * 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.
         */

        private static final int INITIAL_CAPACITY = 16;
        private RunnableScheduledFuture<?>[] queue =
            new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
        private final ReentrantLock lock = new ReentrantLock();
        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.
         */
        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.
         */
        private final Condition available = lock.newCondition();

        /**
         * Sets f's heapIndex if it is a ScheduledFutureTask.
         */
        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.
         */
        private void siftUp(int k, RunnableScheduledFuture<?> key) {
            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.
         */
        private void siftDown(int k, RunnableScheduledFuture<?> key) {
            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.
         */
        private void grow() {
            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.
         */
        private int indexOf(Object x) {
            if (x != null) {
                if (x instanceof ScheduledFutureTask) {
                    int i = ((ScheduledFutureTask) x).heapIndex;
                    // Sanity check; x could conceivably be a
                    // ScheduledFutureTask from some other pool.
                    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;
        }

        public boolean contains(Object x) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return indexOf(x) != -1;
            } finally {
                lock.unlock();
            }
        }

        public boolean remove(Object x) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                int i = indexOf(x);
                if (i < 0)
                    return false;

                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();
            }
        }

        public int size() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return size;
            } finally {
                lock.unlock();
            }
        }

        public boolean isEmpty() {
            return size() == 0;
        }

        public int remainingCapacity() {
            return Integer.MAX_VALUE;
        }

        public RunnableScheduledFuture<?> peek() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return queue[0];
            } finally {
                lock.unlock();
            }
        }

        public boolean offer(Runnable x) {
            if (x == null)
                throw new NullPointerException();
            RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>)x;
            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;
        }

        public void put(Runnable e) {
            offer(e);
        }

        public boolean add(Runnable e) {
            return 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.
         * @param f the task to remove and return
         */
        private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
            int s = --size;
            RunnableScheduledFuture<?> x = queue[s];
            queue[s] = null;
            if (s != 0)
                siftDown(0, x);
            setIndex(f, -1);
            return f;
        }

        public RunnableScheduledFuture<?> poll() {
            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();
            }
        }

        public RunnableScheduledFuture<?> take() throws InterruptedException {
            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);
                        first = null; // don't retain ref while waiting
                        if (leader != null)
                            available.await();
                        else {
                            Thread thisThread = Thread.currentThread();
                            leader = thisThread;
                            try {
                                available.awaitNanos(delay);
                            } finally {
                                if (leader == thisThread)
                                    leader = null;
                            }
                        }
                    }
                }
            } finally {
                if (leader == null && queue[0] != null)
                    available.signal();
                lock.unlock();
            }
        }

        public RunnableScheduledFuture<?> poll(long timeout, TimeUnit unit)
            throws InterruptedException {
            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 {
                        long delay = first.getDelay(NANOSECONDS);
                        if (delay <= 0)
                            return finishPoll(first);
                        if (nanos <= 0)
                            return null;
                        first = null; // don't retain ref while waiting
                        if (nanos < delay || leader != null)
                            nanos = available.awaitNanos(nanos);
                        else {
                            Thread thisThread = Thread.currentThread();
                            leader = thisThread;
                            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();
            }
        }

        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.
         */
        private RunnableScheduledFuture<?> peekExpired() {
            // assert lock.isHeldByCurrentThread();
            RunnableScheduledFuture<?> first = queue[0];
            return (first == null || first.getDelay(NANOSECONDS) > 0) ?
                null : first;
        }

        public int drainTo(Collection<? super Runnable> c) {
            if (c == null)
                throw new NullPointerException();
            if (c == this)
                throw new IllegalArgumentException();
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                RunnableScheduledFuture<?> first;
                int n = 0;
                while ((first = peekExpired()) != null) {
                    c.add(first);   // In this order, in case add() throws.
                    finishPoll(first);
                    ++n;
                }
                return n;
            } finally {
                lock.unlock();
            }
        }

        public int drainTo(Collection<? super Runnable> c, int maxElements) {
            if (c == null)
                throw new NullPointerException();
            if (c == this)
                throw new IllegalArgumentException();
            if (maxElements <= 0)
                return 0;
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                RunnableScheduledFuture<?> first;
                int n = 0;
                while (n < maxElements && (first = peekExpired()) != null) {
                    c.add(first);   // In this order, in case add() throws.
                    finishPoll(first);
                    ++n;
                }
                return n;
            } finally {
                lock.unlock();
            }
        }

        public Object[] toArray() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return Arrays.copyOf(queue, size, Object[].class);
            } finally {
                lock.unlock();
            }
        }

        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            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();
            }
        }

        public Iterator<Runnable> iterator() {
            return new Itr(Arrays.copyOf(queue, size));
        }

        /**
         * Snapshot iterator that works off copy of underlying q array.
         */
        private class Itr implements Iterator<Runnable> {
            final RunnableScheduledFuture<?>[] array;
            int cursor = 0;     // index of next element to return
            int lastRet = -1;   // index of last element, or -1 if no such

            Itr(RunnableScheduledFuture<?>[] array) {
                this.array = array;
            }

            public boolean hasNext() {
                return cursor < array.length;
            }

            public Runnable next() {
                if (cursor >= array.length)
                    throw new NoSuchElementException();
                lastRet = cursor;
                return array[cursor++];
            }

            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                DelayedWorkQueue.this.remove(array[lastRet]);
                lastRet = -1;
            }
        }
    }

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值