JDK8 ScheduledThreadPoolExecutor源码理解

本文深入探讨ScheduledThreadPoolExecutor的原理及应用,包括其关键方法、内部类解析、应用场景等。通过具体示例阐述scheduleAtFixedRate与scheduleWithFixedDelay的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor调度线程池执行器,继承了ThreadPoolExecutor,除了线程池的特性外,还有延迟执行、定期执行任务的特点。

二、使用样例

2.1 关键方法

2.1.1 submit/execute 提交任务

这个方法和普通的线程池一样,执行完就结束了。无延迟或周期调用的功能。

2.1.2 scheduleAtFixedRate以固定周期时间执行

创建一个周期性的任务,第一次执行的延期时间是initialDelay

  • 之后每隔period执行一次,不等待第一次执行完就开始计时
  • 如果任务的执行时间过长,两次执行的开始时间可能会大于周期时间

代码样例1:

任务执行时间为5s,使用延时时间1s,周期6s的参数执行。根据结果可以发现线程池第一次执行时间是提交线程1s后(延时时间),启动后开始计时,6s后再次执行当前任务。

private static void testScheduleAtFixedRate() {
        System.out.println(LocalDateTime.now());
        executor.scheduleAtFixedRate(() -> {
            System.out.println("scheduleAtFixedRate-start-" + LocalDateTime.now());
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("scheduleAtFixedRate-end-" + LocalDateTime.now());

        }, 1, 6, TimeUnit.SECONDS);
    }

结果:

2022-05-23T20:15:30.135
scheduleAtFixedRate-start-2022-05-23T20:15:31.143
scheduleAtFixedRate-end-2022-05-23T20:15:36.143
scheduleAtFixedRate-start-2022-05-23T20:15:37.142
scheduleAtFixedRate-end-2022-05-23T20:15:42.143
scheduleAtFixedRate-start-2022-05-23T20:15:43.141

代码样例2:

任务执行时间为5s,使用延时时间1s,周期1s的参数执行。根据结果可以发现线程池第一次执行时间是提交线程1s后(延时时间),启动后开始计时,5s后再次执行当前任务。

说明即使周期为1s,但上个任务结束时间超过了下次任务执行开始时间,则下次任务开始时间推迟到上次任务结束时间。

下次任务执行开始时间 = MAX(首次任务开始时间+周期时间*次数,上次任务结束时间)

private static void testScheduleAtFixedRateOver() {
        System.out.println(LocalDateTime.now());
        executor.scheduleAtFixedRate(() -> {
            System.out.println("scheduleAtFixedRate-start-" + LocalDateTime.now());
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("scheduleAtFixedRate-end-" + LocalDateTime.now());

        }, 1, 1, TimeUnit.SECONDS);
    }

结果:

2022-05-23T20:18:40.084
scheduleAtFixedRate-start-2022-05-23T20:18:41.090
scheduleAtFixedRate-end-2022-05-23T20:18:46.091
scheduleAtFixedRate-start-2022-05-23T20:18:46.091
scheduleAtFixedRate-end-2022-05-23T20:18:51.091
scheduleAtFixedRate-start-2022-05-23T20:18:51.091
scheduleAtFixedRate-end-2022-05-23T20:18:56.091
scheduleAtFixedRate-start-2022-05-23T20:18:56.091

2.1.3 scheduleWithFixedDelay以固定延迟执行

创建一个周期执行的任务,

  • 第一次执行时间为initialDelay
  • 第一次执行完后延迟delay后开始下一次执行

代码样例:

任务执行时间为5s,使用初始延时时间1s,延时2s的参数执行。根据结果可以发现线程池第一次执行时间是提交线程1s后(初始延时时间),又过了7s(5+2)执行了下一个任务。

下次任务执行时间 = 上次任务执行结束时间 + 延时时间

private static void testScheduleWithFixedDelay() {
        System.out.println(LocalDateTime.now());
        executor.scheduleWithFixedDelay(() -> {
            System.out.println("scheduleAtFixedRate-start-" + LocalDateTime.now());
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("scheduleAtFixedRate-end-" + LocalDateTime.now());

        }, 1, 2, TimeUnit.SECONDS);
    }

结果:

2022-05-23T20:21:59.420
scheduleAtFixedRate-start-2022-05-23T20:22:00.427
scheduleAtFixedRate-end-2022-05-23T20:22:05.427
scheduleAtFixedRate-start-2022-05-23T20:22:07.429
scheduleAtFixedRate-end-2022-05-23T20:22:12.430
scheduleAtFixedRate-start-2022-05-23T20:22:14.432

三、应用场景

Spring的@Scheduled注解实现定时任务或者延时任务

看Spring源码,描述流程

四、相关知识

4.1 流程图

流程图

4.2 体系结构

4.3 比较

Timer

五、考察点

六、源码解析

6.1 ScheduledThreadPoolExecutor类

6.1.1 成员变量

    /**
     * 处于shutdown状态,已经处于阻塞队列的任务能否继续执行
     */
    private volatile boolean continueExistingPeriodicTasksAfterShutdown;

    /**
     * 处于shutdown状态,已经处于阻塞队列的任务能否继续执行
     */
    private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
    /**
     * 如果取消的话,从队列中移除任务。
     * 因为可能是周期任务,只取消本次执行,不取消周期执行
     */
    private volatile boolean removeOnCancel = false;

    /**
     * 为相同延时的任务提供的顺序编号,保证进入阻塞队列的任务之间FIFO的顺序
     */
    private static final AtomicLong sequencer = new AtomicLong();

6.1.2 scheduleAtFixedRate将任务以固定周期执行

/**
     * 创建一个周期性的任务,第一次执行的延期时间是initialDelay
     * 之后每隔period执行一次,不等待第一次执行完就开始计时
     * 如果任务的执行时间过长,两次执行的开始时间会大于周期时间
     * 
     * 举例:设置执行时间点为 1(初始延时),4(间隔为3)7,10,13
     * 假如第一次执行时间为4,第二次执行时间为1,则执行的时间点位
     * 1,5,7,10,13
     * @param command 任务
     * @param initialDelay 第一次延期时间
     * @param period 周期间隔
     * @param unit 单位
     * @return 周期任务
     */
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (period <= 0)
            throw new IllegalArgumentException();
        // 创建一个周期任务,延时时间为initialDelay
        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;
    }

有三个关键的地方:

  • 创建ScheduledFutureTask对象
  • 设置下个周期执行的任务
  • 将ScheduledFutureTask对象加入阻塞队列并预启动一个Worker线程

  ScheduledFutureTask继承FutureTask,实现了Runnable方法,因此其对象作为任务提交到阻塞队列,并且被线程取出来后,执行的是run方法。
  下个周期的任务是t,t由decorateTask对上个任务进行扩展,这里默认不做扩展。
  延迟执行delayExecute,先将任务加到阻塞队列里,然后预启动一个线程,等待将来线程池中的Worker从阻塞队列中获取任务。

6.1.3 canRunInCurrentRunState判断当前状态能否运行

用在任务已提交,但线程池已关闭(shutdown)的场景。

   /**
     * 判断当前状态是否能运行
     * @param periodic 是否为周期性的任务
     * @return 是否能够运行
     */
    boolean canRunInCurrentRunState(boolean periodic) {
        return isRunningOrShutdown(periodic ?
                // 如果是周期性的,返回判断关闭后能否执行周期性任务
                continueExistingPeriodicTasksAfterShutdown :
                // 否则返回判断能否执行延迟任务
                executeExistingDelayedTasksAfterShutdown);
    }

6.1.4 delayExecute延时执行,提交任务并预启动Worker

  /**
     * 延时执行
     * @param task 任务
     */
    private void delayedExecute(RunnableScheduledFuture<?> task) {
        // 线程池关闭则拒绝任务
        if (isShutdown())
            reject(task);
        else {
            // 直接放到延时阻塞队列里
            super.getQueue().add(task);
            // 再判断是否关闭,状态>=SHUTDOWN
            if (isShutdown() &&
                    // 当前状态不允许运行任务
                    !canRunInCurrentRunState(task.isPeriodic()) &&
                    // 移除任务成功
                    remove(task))
                // 不中断地取消
                task.cancel(false);
            else
                // 预启动一个线程
                ensurePrestart();
        }
    }

6.1.5 reExecutePeriodic任务执行结束后,重新将任务添加到阻塞队列

 /**
     * 重排队一个周期任务
     * 不会拒绝策略而是直接丢掉任务
     * @param task the task
     */
    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
        // 判断周期性任务在当前状态能否执行
        if (canRunInCurrentRunState(true)) {
            // 阻塞队列加入该任务
            super.getQueue().add(task);
            // 如果当前装填不能运行周期性任务 并且 移除阻塞队列成功
            if (!canRunInCurrentRunState(true) && remove(task))
                // 不中断地取消任务
                task.cancel(false);
            else
                // 预启动一个线程
                ensurePrestart();
        }
    }

6.1.6 onShutdown父类的shutdown会调用,线程池关闭时的动作

 /**
     * 父类的shutdown会调用
     * 关闭线程池时对两种任务的处理
     */
    @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();
    }

6.1.7 decorateTask装饰任务

   /**
     * 用户可自定义的扩展方法,用于装饰任务
     */
    protected <V> RunnableScheduledFuture<V> decorateTask(
            Runnable runnable, RunnableScheduledFuture<V> task) {
        return task;
    }

6.1.8 triggerTime 计算delay的值

  /**
     * 如果delay小于Long最大值的一半,则直接返回计算结果
     * 否则需要计算delay的值
     */
    long triggerTime(long delay) {
        // now + delay or Long + time
        return now() +
                ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
    }

6.1.9 overflowFree防止compareTo中减法发生溢出

  /**
     *
     * 防止compareTo中减法发生溢出
     * 如果delay - 堆顶延迟时间 发生了溢出,就将delay设置为 Long + headDelay
     * delay值变小了
     */
    private long overflowFree(long delay) {
        Delayed head = (Delayed) super.getQueue().peek();
        if (head != null) {
            // time - now
            long headDelay = head.getDelay(NANOSECONDS);
            // 堆顶的任务已经到期了
            if (headDelay < 0 && (delay - headDelay < 0))
                // Long + time -now
                delay = Long.MAX_VALUE + headDelay;
        }
        return delay;
    }

6.1.10 schedule提交延时但非周期性任务

 /**
     * 定时执行
     * @param command 任务
     * @param delay 延迟时间
     * @param unit 单位
     * @return 结果
     */
    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        // 装饰任务
        RunnableScheduledFuture<?> t = decorateTask(command,
                new ScheduledFutureTask<Void>(command, null,
                        triggerTime(delay, unit)));
        // 延迟执行
        delayedExecute(t);
        // 返回Future
        return t;
    }

6.1.11 scheduleWithFixedDelay延时周期任务,以固定延时执行

    /**
     * 创建一个周期执行的任务,第一次执行时间为initialDelay
     * 第一次执行完后延迟delay后开始下一次执行
     * @param command 任务
     * @param initialDelay 第一次执行时间
     * @param delay 延时
     * @param unit 单位
     * @return 任务结果
     */
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (delay <= 0)
            throw new IllegalArgumentException();
        // 这里delay传的是负值
        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;
    }

6.2 内部类ScheduledFutureTask

6.2.1 内部类的成员变量

    /**
         * 两个任务有相同延时时间时,按照FIFO入队,该变量是为相同延时任务提供的顺序编号
         */
        private final long sequenceNumber;

        /**
         * 任务执行的时刻。任何一个时间点都可以用long去表示
         */
        private long time;

        /**
         * 正数代表固定速率执行,为scheduleAtFixedRate提供服务
         * 负数代表固定延时执行,为scheduleWithFixedDelay提供服务
         * 0代表不重复执行
         */
        private final long period;

        /**
         * reExecutePeriodic执行后重新入队的任务
         */
        RunnableScheduledFuture<V> outerTask = this;

        /**
         * 延迟队列的索引,支持快速取消,-1代表不在队列中
         */
        int heapIndex;

6.2.2 getDelay获取任务还需要多久执行

    /**
         * 获取任务的剩余等待时间
         * @param unit 单位
         * @return 剩余等待时间
         */
        public long getDelay(TimeUnit unit) {
            return unit.convert(time - now(), NANOSECONDS);
        }
        final long now() {
        	return System.nanoTime();
   		}

6.2.3 compareTo用于阻塞队列中元素的排序

/**
         * 比较两个延时任务的延时时间,如果相同使用序列号比较
         * @param other 被比较的元素
         * @return 比较结果
         */
        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;
        }

6.2.4 isPeriodic是否周期性任务

 /**
         * 判断是否为周期性的任务
         * period为0代表只执行一次
         */
        public boolean isPeriodic() {
            return period != 0;
        }

6.2.5 setNextRunTime设置下次执行任务的时间

是 scheduleAtFixedRate和scheduleWithFixedDelay功能区分的关键代码

   /**
         * 对于周期性的任务,设置下一次运行时间
         * 这里是 scheduleAtFixedRate和scheduleWithFixedDelay区分的关键代码
         */
        private void setNextRunTime() {
            long p = period;
            // 如果p大于0,则下次执行任务的时间是上次任务的开始时间+执行周期
            if (p > 0)
                time += p;
            else
                // 如果p小于等于0,则下次执行时间是上次任务结束时间+执行周期
                time = triggerTime(-p);
        }

6.2.6 cancel取消任务

复用了父类的取消逻辑

  /**
         * 取消任务
         * @param mayInterruptIfRunning 是否中断
         * @return 取消成功
         */
        public boolean cancel(boolean mayInterruptIfRunning) {
            // 取消任务,将会将任务从阻塞中唤醒并结束,返回结果为null,判断是否取消成功,
            boolean cancelled = super.cancel(mayInterruptIfRunning);
            // 取消成功,并且 取消时需要从阻塞队列移除 并且 延迟队列的索引大于等于0
            if (cancelled && removeOnCancel && heapIndex >= 0)
                // 从阻塞队列中移除当前任务
                remove(this);
            // 返回最终是否移除成功
            return cancelled;
        }

6.2.7 run任务提交后的执行逻辑

如果是周期性的任务,在当前任务执行后会设置下次执行时间,并重新进入阻塞队列。

    /**
         * 重写FutureTask的方法,提交到线程池时执行的是该方法的逻辑
         */
        public void run() {
            // 判断是否是周期性的任务
            boolean periodic = isPeriodic();
            // 如果当前状态不能运行
            if (!canRunInCurrentRunState(periodic))
                // 取消当前任务
                cancel(false);
            // 如果不是周期性的任务(只执行一次)
            else if (!periodic)
                // 直接启动任务
                ScheduledFutureTask.super.run();
            // 如果是周期性的任务,并且运行结束后状态重置成功(中间运行抛出异常或者被取消了则返回失败)
            else if (ScheduledFutureTask.super.runAndReset()) {
                // 设置下一次运行的时间
                setNextRunTime();
                reExecutePeriodic(outerTask);
            }
        }

6.3 内部类DelayedWorkQueue

底层使用数组维护最小堆,使用ReentrantLock和Condition实现线程等待

6.3.1 内部属性

   // 默认长度
        private static final int INITIAL_CAPACITY = 16;
        // 底层是数组,默认长度是16,是最小堆
        private RunnableScheduledFuture<?>[] queue =
                new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
        private final ReentrantLock lock = new ReentrantLock();
        // 当前数据元素个数
        private int size = 0;
        // 队列头所在的leader线程。假如没有leader,在take时每个线程都会等待指定时间,大家一起被唤醒抢占资源,消耗性能
        private Thread leader = null;
        // 队列头的任务延时时间到了,或者新线程可能需要成为leader,用来唤醒等待线程
        private final Condition available = lock.newCondition();

6.3.2 内部方法


        /**
         * 设置任务在堆中的位置
         */
        private void setIndex(RunnableScheduledFuture<?> f, int idx) {
            if (f instanceof ScheduledFutureTask)
                ((ScheduledFutureTask) f).heapIndex = idx;
        }


        /**
         * 先把任务放到堆尾,然后向上调整位置
         * @param k 任务最开始放到堆的位置
         * @param key 任务
         */
        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;
            }
            // 得到的k是最终任务应该放到的位置
            queue[k] = key;
            // 设置任务在堆中的位置为k
            setIndex(key, k);
        }

        /**
         *  将任务放到堆k的位置,让后向下计算它在堆的实际位置
         */
        private void siftDown(int k, RunnableScheduledFuture<?> key) {
            // half是k最远能到达位置的下一个位置
            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];
                // 如果当前值比子节点的最小值还要小,则当前位置k就是要key最后放的位置
                if (key.compareTo(c) <= 0)
                    break;
                // 当前位置跟比较小的结点交换位置
                queue[k] = c;
                setIndex(c, k);
                // k变到较小的位置
                k = child;
            }
            // 最终将key放到查找的到的位置
            queue[k] = key;
            setIndex(key, k);
        }

        /**
         * 队列扩容,拿到锁的时候才能操作。
         * 容量每次提升50%
         */
        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);
        }

        /**
         * 移除某元素,向上或向下调整
         */
        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) {
                    // 把replacement放到i的位置,然后向下调整replacement位置
                    siftDown(i, replacement);
                    // 假如把replacement放到i位置后,直接就是最小的值,则他有可能比它现在的父节点小,需要向上调整
                    if (queue[i] == replacement)
                        siftUp(i, replacement);
                }
                return true;
            } finally {
                lock.unlock();
            }
        }

        /**
         * 不受容量限制,永远返回Integer.MAX_VALUE;
         */
        public int remainingCapacity() {
            return Integer.MAX_VALUE;
        }

        /**
         * 入队
         * @param x 任务
         * @return 是否入队成功
         */
        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;
                    // 设置该任务在堆中的位置是数组下标0
                    setIndex(e, 0);
                } else {
                    // i是新节点入队的初始位置,任务入队,调整位置
                    siftUp(i, e);
                }
                // 如果堆顶是当前任务,
                if (queue[0] == e) {
                    // 说明此时没有线程获取过堆顶任务
                    leader = null;
                    // 唤醒等待任务的线程
                    available.signal();
                }
            } finally {
                lock.unlock();
            }
            return true;
        }

        /**
         * 弹出堆顶元素,堆尾放到堆顶,重新调整堆
         */
        private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
            // 元素数量-1
            int s = --size;
            // 获取队尾元素
            RunnableScheduledFuture<?> x = queue[s];
            // 队尾置空
            queue[s] = null;
            // 把元素放到堆顶,然后向下计算该元素的位置
            if (s != 0)
                siftDown(0, x);
            // 设置原来堆顶的元素在数组中的位置为-1.相当于移除队列
            setIndex(f, -1);
            // 返回堆顶元素
            return f;
        }

        /**
         * 非阻塞式获取数据,如果此时获取不到返回null
         */
        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];
                    // 堆顶为null则等待
                    if (first == null)
                        available.await();
                    else {
                        // 获取任务的剩余等待时间
                        long delay = first.getDelay(NANOSECONDS);
                        // 如果已经达到执行时间,则堆顶出队
                        if (delay <= 0)
                            return finishPoll(first);
                        // 等待的时候不保持引用,被唤醒后要重新从堆顶拿
                        first = null;
                        // leader被占用的时候,说明还有其它线程也在等待,设置当前线程无期限等待。
                        if (leader != null)
                            available.await();
                        else {
                            // 如果leader为null
                            // 记录当前线程
                            Thread thisThread = Thread.currentThread();
                            // leader为当前线程
                            leader = thisThread;
                            try {
                                // 等待delay时间
                                available.awaitNanos(delay);
                            } finally {
                                // 如果leader是当前线程
                                if (leader == thisThread)
                                    // leader置为null
                                    leader = null;
                            }
                        }
                    }
                }
            } finally {
                // 如果堆中还有元素,并且此时没有线程占据leader,则唤醒下一个线程
                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();
            }
        }


        /**
         * 堆顶过期则弹出
         */
        private RunnableScheduledFuture<?> peekExpired() {
            RunnableScheduledFuture<?> first = queue[0];
            // 队首是null或者当前没有到期的任务,则返回null,否则返回堆顶任务
            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();
            }
        }
        /**
         * 将所有到期的任务从堆中移到新的集合中,并返回移动的数量,最多可以移动maxElements个
         */
        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 Iterator<Runnable> iterator() {
            return new Itr(Arrays.copyOf(queue, size));
        }

        /**
         * 内部类处理内部数组副本的迭代器
         */
        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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值