Java ~ Collection/Executor ~ DelayQueue【源码】

33 篇文章 0 订阅
17 篇文章 0 订阅

前言


 相关系列

 涉及内容

一 DelayQueue(延迟队列)类源码及机制详解


 类

    DelayQueue(延迟队列)类是BlockingQueue(阻塞队列)接口的实现类之一,基于数组实现,特点是元素会被延迟头部移除。延迟队列类不支持任意类型的元素,其元素被强制指定为Delayed(延迟)接口对象,即延迟接口实现类对象,否则会抛出类型转换异常。之所以强制类型是因为延迟队列会调用延迟接口定义的getDelay(TimeUnit unit)方法来获取元素的剩余延迟来实现精确延迟,因此延迟接口实现类必须实现该方法以返回有效的剩余延迟。除此之外,由于底层使用PriorityQueue(优先级队列)类的原因,延迟接口实现类还必须实现Comparable(比较能力)接口定义的compareTo(T o)方法以实现元素之间剩余延迟时间的比较,该知识点的详细内容会在下文详述。

    延迟队列类不允许存null值,或者说阻塞队列接口的所有实现类都不允许存null值。null被作为poll()及peek()方法表示延迟队列不存在元素的标记值,因此所有阻塞队列接口实现类都不允许存null值。

    延迟队列类是无界队列,意味着其最大容量理论上只受限于堆内存的大小。延迟队列类底层使用优先级队列类实现,由于其扩容机制的存在,延迟队列类也被纳入无界队列的范围中。但虽说如此,优先级队列类在实现中还受到数组实现与int类型影响,因此延迟队列的最大容量实际上为Integer.MAX_VALUE。由于其无界队列的定义,为了掩盖实际实现中受到的限制,当其保存的元素总数触达上限时会模拟堆内存不足的场景手动抛出内存溢出错误。

    延迟队列类是线程安全的,或者说阻塞队列接口的所有实现类都是线程安全的,其接口定义中强制要求实现类必须线程安全。延迟队列类采用“单锁”线程安全机制,即使用一个ReentrantLock(可重入锁)类对象来保证整体的线程安全。

    延迟队列类的迭代器是弱一致性,即可能迭代到已移除的元素及无法迭代到新插入的元素。延迟队列的迭代器实现非常直接(或者说过于直接了),其会直接将数据拷贝一份快照存入生成的迭代器中以进行迭代。这么做的好处是迭代器的实现非常的简单,但缺点也明显,当延迟队列的元素总数较大或生成的迭代器数量较多时对内存的消耗会非常严重。

    延迟队列类虽然与阻塞队列接口一样都被纳入Executor(执行器)框架的范畴,但同时也是Collection(集)框架的成员。

/**
 * An unbounded {@linkplain BlockingQueue blocking queue} of {@code Delayed} elements, in which an element can only be taken
 * when its delay has expired.  The <em>head</em> of the queue is that {@code Delayed} element whose delay expired furthest in
 * the past.  If no delay has expired there is no head and {@code poll} will return {@code null}. Expiration occurs when an element's
 * {@code getDelay(TimeUnit.NANOSECONDS)} method returns a value less than or equal to zero.  Even though unexpired
 * elements cannot be removed using {@code take} or {@code poll}, they are otherwise treated as normal elements. For example, the
 * {@code size} method returns the count of both expired and unexpired elements. This queue does not permit null elements.
 * 一个延迟元素的无界阻塞队列。一个元素只能在它的延迟过期后才能拿取。队列的头是在过去延迟最远过期的延迟元素(即最早
 * 过期的元素)。如果没有延迟已过期则没有头并且poll()方法将返回null。当一个元素的getDelay(TimeUnit.NANOSECONDS)
 * 方法值小于或等于0则发生元素过期。虽然未过期的元素无法使用take()或poll()方法移除,但他们也会被看做普通元素。例如,
 * size()方法返回已过期与未过期元素的总数。该队列不允许null元素。
 * <p>
 * This class and its iterator implement all of the <em>optional</em> methods of the {@link Collection} and {@link Iterator} interfaces.
 * The Iterator provided in method {@link #iterator()} is <em>not</em> guaranteed to traverse the elements of the DelayQueue in
 * any particular order.
 * 该类与它的迭代器实现了集与迭代接口的所有可选方法。通过iterator()方法提供的迭代器不保证延迟队列的元素按特定的顺序遍历。
 * <p>
 * This class is a member of the <a href="{@docRoot}/../technotes/guides/collections/index.html"> Java Collections Framework</a>.
 * 该类是Java集框架的成员。
 *
 * @param <E> the type of elements held in this collection 集持有的元素
 * @author Doug Lea
 * @since 1.5
 */
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E> {
    ...
}

 字段

    lock(锁) —— 持有一个可重入锁对象,用于保证延迟队列的线程安全性。

    /**
     * @Description: 名称:锁
     * @Description: 作用:持有一个可重入锁对象,用于保证延迟队列的线程安全性。
     * @Description: 逻辑:~
     */
    private final transient ReentrantLock lock = new ReentrantLock();

    q(优先级队列) —— 持有一个优先级队列对象,用于实际排序并保存元素。

    /**
     * @Description: 名称:优先级队列
     * @Description: 作用:持有一个优先级队列对象,用于实际排序并保存元素。
     * @Description: 逻辑:~
     */
    private final PriorityQueue<E> q = new PriorityQueue<E>();

    leader(领导者) —— 持有专属等待头元素延迟过期的线程。

    /**
     * Thread designated to wait for the element 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 an element 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.
     * 线程指定等待队列的头元素。领导者 - 追随者模式的变种提供最小限度的非必要定时等待。当一个线程成为领导者,它只等待
     * 下个延迟「元素」过期,但是其它线程会无限期的等待。领导者线程必须通知在take()或poll()方法返回前通知这些其它线程,
     * 除非这些其它线程在期间成为领导者。每当队列的头被一个具有较早过期时间的元素替换时,leader字段将被重置为null,从
     * 而失效,并向一些等待中的线程(不一定是当前的leader)发出信号。因此等待线程必须准备好在等待过程中获得和失去领导
     * 地位。
     *
     * @Description: 名称:领导者
     * @Description: 作用:持有专属等待头元素延迟过期的线程。
     * @Description: 逻辑:~
     */
    private Thread leader = null;

    available(可用条件) —— 用于保存因为没有延迟元素而需要等待的线程。

    /**
     * Condition signalled when a newer element 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();

 构造方法

    public DelayQueue() —— 延迟队列 —— 创建一个延迟队列。

    /**
     * Creates a new {@code DelayQueue} that is initially empty.
     * 创建一个初始为空的延迟队列。
     *
     * @Description: 名称:~
     * @Description: 作用:创建一个延迟队列。
     * @Description: 逻辑:~
     */
    public DelayQueue() {
    }

    public DelayQueue(Collection<? extends E> c)—— 延迟队列 —— 创建一个包含指定集中所有元素的延迟队列。

    /**
     * Creates a {@code DelayQueue} initially containing the elements of the given collection of {@link Delayed} instances.
     * 创建一个初始包含延迟实例的指定集的元素的延迟队列(即指定集中的元素必须是延迟元素)。
     *
     * @param c the collection of elements to initially contain  用于初始包含的元素集
     * @throws NullPointerException if the specified collection or any of its elements are null
     *                              空指针异常:如果指定集或其任意元素为null
     * @Description: 名称:~
     * @Description: 作用:创建一个包含指定集中所有元素的延迟队列。
     * @Description: 逻辑:~
     */
    public DelayQueue(Collection<? extends E> c) {
        this.addAll(c);
    }

 方法

    public boolean add(E e) —— 新增 —— 向延迟队列添加指定元素。该方法是插入/放置操作“异常”形式的实现,当延迟队列存在剩余容量时插入/放置成功并返回true;否则抛出非法状态异常。虽说定义如此,但实际由于延迟队列是真正的无界队列,最大 容量只受限于堆内存的大小,故而永远不会抛出非法状态异常,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列是基于优先级队列实现的,因此最大容量实际还受限于int的最大长度Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
    方法直接调用offer(E e)方法执行。

    /**
     * Inserts the specified element into this delay queue.
     * 插入指定元素至延迟队列。
     *
     * @param e the element to add 用于新增的元素
     * @return {@code true} (as specified by {@link Collection#add}) true
     * @throws NullPointerException if the specified element is null
     *                              空指针异常:如果指定元素无null
     * @Description: 名称:新增
     * @Description: 作用:向延迟队列添加指定元素。该方法是插入/放置操作“异常”形式的实现,当延迟队列存在剩余容量时插入
     * @Description: /放置成功并返回true;否则抛出非法状态异常。虽说定义如此,但实际由于延迟队列是真正的无界队列,最大
     * @Description: 容量只受限于堆内存的大小,故而永远不会抛出非法状态异常,而只会在堆内存不足时抛出内存溢出错误。由
     * @Description: 于延迟队列是基于优先级队列实现的,因此最大容量实际还受限于int的最大长度Integer.MAX_VALUE。当元素
     * @Description: 总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
     * @Description: 逻辑:方法直接调用offer(E e)方法执行。
     */
    public boolean add(E e) {
        return offer(e);
    }

    public boolean offer(E e) —— 提供 —— 向延迟队列添加指定元素。该方法是插入/放置操作“特殊值”形式的实现,当延迟队列存在剩余容量时插入/放置成功并返回true;否则返回false。虽说定义如此,但实际由于延迟队列是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会返回false,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列是基于优先级队列实现的,因此最大容量实际还受限于int的最大长度Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
    方法在悲观锁的保护下调用底层优先级队列的offer(E e)方法执行。在调用完成后,会判断优先级队列的头元素是否是指定元素。如果是,则说明指定元素的延迟时间是所有元素中最长的,因此针对旧头元素设定的领导者会失效,需要将之取消。

    /**
     * Inserts the specified element into this delay queue.
     * 插入指定元素至延迟队列。
     *
     * @param e the element to add 用于新增的元素
     * @return {@code true} true  true
     * @throws NullPointerException if the specified element is null
     *                              空指针异常:如果指定元素无null
     * @Description: 名称:提供
     * @Description: 作用:向延迟队列添加指定元素。该方法是插入/放置操作“特殊值”形式的实现,当延迟队列存在剩余容量时插
     * @Description: 入/放置成功并返回true;否则返回false。虽说定义如此,但实际由于延迟队列是真正的无界队列,最大容量只
     * @Description: 受限于堆内存的大小,故而永远不会返回false,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列是基
     * @Description: 于优先级队列实现的,因此最大容量实际还受限于int的最大长度Integer.MAX_VALUE。当元素总数触达该上限
     * @Description: 时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
     * @Description: 逻辑:方法在悲观锁的保护下调用底层优先级队列的offer(E e)方法执行。在调用完成后,会判断优先级队列的
     * @Description: 头元素是否是指定元素。如果是,则说明指定元素的延迟时间是所有元素中最长的,因此针对旧头元素设定的
     * @Description: 领导者会失效,需要将之取消。
     */
    public boolean offer(E e) {
        // 加锁,保证线程安全问题。
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 调用优先级队列的offer()方法。
            q.offer(e);
            // 调用优先级队列的peek()方法获取队列头元素。如果队列头元素是指定元素,则说明当前元素是延迟时间最短的元素。在
            // 这种情况下针对原先的头元素的而设置的领导者及其限时等待的操作都会失效,因此需要将之作废重新设置。
            if (q.peek() == e) {
                // 遗忘当前的领导者,并唤醒可用条件中的一个线程去竞争领导者(如果存在等待线程的话)。
                leader = null;
                available.signal();
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

    public void put(E e)—— 新增 —— 向延迟队列添加指定元素。该方法是插入/放置操作“异常”形式的实现,当延迟队列存在剩余容量时插入/放置成功并返回true;否则抛出非法状态异常。虽说定义如此,但实际由于延迟队列是真正的无界队列,最大 容量只受限于堆内存的大小,故而永远不会抛出非法状态异常,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列是基于优先级队列实现的,因此最大容量实际还受限于int的最大长度Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
    方法直接调用offer(E e)方法执行。

    /**
     * Inserts the specified element into this delay queue. As the queue is unbounded this method will never block.
     * 新增指定元素至延迟队列。由于队列是无界的因此该方法不会阻塞。
     *
     * @param e the element to add 用于新增的元素
     * @throws NullPointerException {@inheritDoc} 空指针异常
     * @Description: 名称:放置
     * @Description: 作用:向延迟队列添加指定元素。该方法是插入/放置操作“阻塞”形式的实现,当延迟队列存在剩余容量时插入
     * @Description: /放置成功;否则等待至有剩余容量为止。虽说定义如此,但实际由于延迟队列是真正的无界队列,最大容量只
     * @Description: 受限于堆内存的大小,故而永远不会等待,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列是基于优
     * @Description: 先级队列实现的,因此最大容量实际还受限于int的最大长度Integer.MAX_VALUE。当元素总数触达该上限时,
     * @Description: 为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
     * @Description: 逻辑:方法直接调用offer(E e)方法执行。
     */
    public void put(E e) {
        offer(e);
    }

    public boolean offer(E e, long timeout, TimeUnit unit) —— 提供 —— 向延迟队列添加指定元素。该方法是插入/放置操作“超时”形式的实现,当延迟队列存在剩余容量时插入/放置成功并返回true;否则在指定的等待时间内等待至有剩余容量,超出等待时间则返回false。虽说定义如此,但实际由于延迟队列是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会等待,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列是基于优先级队列实现的,因此最大容量实际还受限于int的最大长度Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
    方法直接调用offer(E e)方法执行。

    /**
     * Inserts the specified element into this delay queue. As the queue is unbounded this method will never block.
     * 新增指定元素至延迟队列。由于队列是无界的因此该方法不会阻塞。
     *
     * @param e       the element to add 用于新增的元素
     * @param timeout This parameter is ignored as the method never blocks 由于方法不会阻塞,该参数是被忽略的
     * @param unit    This parameter is ignored as the method never blocks 由于方法不会阻塞,该参数是被忽略的
     * @return {@code true}
     * @throws NullPointerException {@inheritDoc} 空指针异常
     * @Description: 名称:提供
     * @Description: 作用:向延迟队列添加指定元素。该方法是插入/放置操作“超时”形式的实现,当延迟队列存在剩余容量时插入/
     * @Description: 放置成功并返回true;否则在指定的等待时间内等待至有剩余容量,超出等待时间则返回false。虽说定义如此,
     * @Description: 但实际由于延迟队列是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会等待,而只会在堆内
     * @Description: 存不足时抛出内存溢出错误。由于延迟队列是基于优先级队列实现的,因此最大容量实际还受限于int的最大长
     * @Description: 度Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。
     * @Description: 逻辑:方法直接调用offer(E e)方法执行。
     */
    public boolean offer(E e, long timeout, TimeUnit unit) {
        return offer(e);
    }

    public E poll() —— 轮询 —— 从延迟队列(优先级队列)的队头移除并获取延迟元素。该方法是移除/拿取方法中“特殊值”形式的实现,当延迟队列存在延迟元素时移除/拿取并返回延迟元素;否则返回null。
    方法在悲观锁的保护下,从底层的优先级队列中获取头元素。如果头元素不存在或者头元素还存在剩余的延迟时间则说明延迟队列不存在延迟元素,直接返回null;否则说明头元素是延迟元素,移除/拿取优先级队列中的头元素并返回。

    /**
     * Retrieves and removes the head of this queue, or returns {@code null} if this queue has no elements with an expired delay.
     * 检索并移除队列的头元素,或如果队列没有延迟到期的元素则返回null。
     *
     * @return the head of this queue, or {@code null} if this queue has no elements with an expired delay
     * 队列的头,或如果当前队列没有延迟到期的元素则返回null
     * @Description: 名称:轮询
     * @Description: 作用:从延迟队列(优先级队列)的队头移除并获取延迟元素。该方法是移除/拿取方法中“特殊值”形式的实现,
     * @Description: 当延迟队列存在延迟元素时移除/拿取并返回延迟元素;否则返回null。
     * @Description: 逻辑:方法在悲观锁的保护下,从底层的优先级队列中获取头元素。如果头元素不存在或者头元素还存在剩余
     * @Description: 的延迟时间则说明延迟队列不存在延迟元素,直接返回null;否则说明头元素是延迟元素,移除/拿取优先级队
     * @Description: 列中的头元素并返回。
     */
    public E poll() {
        // 加锁。
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 获取优先级队列的头元素(快照)。
            E first = q.peek();
            if (first == null || first.getDelay(NANOSECONDS) > 0)
                // 如果头元素(快照)为null或者头元素(快照)的剩余延迟时间大于0(说明队列中没有元素到期),直接返回null。
                return null;
            else
                // 如果头元素(快照)已到期,则直接返回。
                return q.poll();
        } finally {
            lock.unlock();
        }
    }

    public E take() throws InterruptedException —— 拿取 —— 从延迟队列(优先级队列)的队头移除并获取延迟元素。该方法是移除/拿取方法中“阻塞”形式的实现,当延迟队列存在延迟元素时移除/拿取并返回延迟元素;否则等待至有延迟元素后返回延迟元素。
    方法在悲观锁的保护下,从底层的优先级队列中获取头元素。如果头元素不存在,说明不存在延迟元素,当前线程进入无限等待;如果头元素存在但未延迟到期,也说明不存在延迟元素,但当前线程的等待时间需要根据领导者进行判断。如果存在领导者,说明已经有其它线程专属等待头元素成为延迟元素,当前线程进入无限等待;否则令当前线程专属等待头元素成为延迟元素,即令当前线程成为领导者,并将头元素的剩余延迟时间作为当前线程的限时等待时间。如果头元素存在且延时到期,说明存在延迟元素,移除/拿取优先级队列中的头元素并返回。
    需要注意的是,领导者并不一定能移除/拿取到首个延迟元素,虽然其概率很大,但也有可能会被外来线程或限时等待线程获取。

    /**
     * Retrieves and removes the head of this queue, waiting if necessary until an element with an expired delay is available on this
     * queue.
     * 检索并移除队列的头,如果必要则等待直至队列中的一个延迟到期的元素可用。
     *
     * @return the head of this queue 队列的头
     * @throws InterruptedException {@inheritDoc} 中断异常
     * @Description: 名称:拿取
     * @Description: 作用:从延迟队列(优先级队列)的队头移除并获取延迟元素。该方法是移除/拿取方法中“阻塞”形式的实现,
     * @Description: 当延迟队列存在延迟元素时移除/拿取并返回延迟元素;否则等待至有延迟元素后返回延迟元素。
     * @Description: 逻辑:方法在悲观锁的保护下,从底层的优先级队列中获取头元素。如果头元素不存在,说明不存在延迟元素,
     * @Description: 当前线程进入无限等待;如果头元素存在但未延迟到期,也说明不存在延迟元素,但当前线程的等待时间需要
     * @Description: 根据领导者进行判断。如果存在领导者,说明已经有其它线程专属等待头元素成为延迟元素,当前线程进入无
     * @Description: 限等待;否则令当前线程专属等待头元素成为延迟元素,即令当前线程成为领导者,并将头元素的剩余延迟时
     * @Description: 间作为当前线程的限时等待时间。如果头元素存在且延时到期,说明存在延迟元素,移除/拿取优先级队列中
     * @Description: 的头元素并返回。
     * @Description: 需要注意的是,领导者并不一定能移除/拿取到首个延迟元素,虽然其概率很大,但也有可能会被外来线程或
     * @Description: 限时等待线程获取。
     */
    public E take() throws InterruptedException {
        // 悲观锁保护。
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            //
            for (; ; ) {
                // 获取优先级队列的头元素。
                E first = q.peek();
                if (first == null)
                    // 如果没有头元素,则说明没有元素,令当前线程陷入永久等待,直至被唤醒。
                    available.await();
                else {
                    // 如果存在头元素,则获取头元素的剩余延迟时间。如果延迟到期,则直接返回。
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0)
                        return q.poll();
                    // don't retain ref while waiting
                    // 不在等待期间保存引用

                    // 由于头元素在当前线程等待期间可能会被其它线程移除/拿取,因此如果不把当前快照遗忘,会导致该头元素无法被GC
                    // 回收。
                    first = null;

                    // 判断是否存在领导者。
                    if (leader != null)
                        // 如果存在领导者,说明已经有线程在等待当前头元素,因此当前线程进入无限等待状态,直至被唤醒。
                        available.await();
                    else {
                        // 如果不存在领导者,则将当前线程设置为领导者。
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            // 令领导者根据当前头元素的剩余延迟时间进行限时等待,因此可知头元素的到期时刻与领导者的唤醒时刻基本是一
                            // 致的。因此当领导者自身唤醒时基本上是可以直接获取延时元素的。
                            available.awaitNanos(delay);
                        } finally {
                            // 在插入/获取中,如果插入了一个新的元素,并且该延迟元素的延迟时间是当前元素中最小的,则意味着它会排序到
                            // 底层优先级队列的头部。如此一来,针对前头元素的延迟时间设置的领导者就失效了,因此就可能出现当前线程被
                            // 唤醒后发现自己不再是领导者的情况(可能为null,也可能是其它线程)。但是如果领导者依然是当前线程,则需要
                            // 将之进行遗忘,因为其要被重新获取元素。当然,虽然该线程是与头元素匹配的领导者,但不代表其一定能获取,
                            // 只是概率更大而已,头元素可能会被其它外来的线程获取。
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            // 如果当前没有领导者,并且存在头元素,则唤醒条件中的一个线程。这是为了在第一个延期节点被领导者移除/拿取之后,
            // 后续的线程能够继续将剩下的延迟节点继续的移除/拿取。直至有新的元素加入,或者所有的延迟节点都被移除/拿取。
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

    public E poll(long timeout, TimeUnit unit) throws InterruptedException —— 轮询 —— 从延迟队列(优先级队列)的队头移除并获取延迟元素。该方法是移除/拿取方法中“阻塞”形式的实现,当延迟队列存在延迟元素时移除/拿取并返回延迟元素;否则等待至有延迟元素后返回延迟元素从延迟队列(优先级队列)的队头移除并获取延迟元素。该方法是移除/拿取方法中“超时”形式的实现,当延迟队列存在延迟元素时移除/拿取并返回延迟元素;否则等待指定的等待时间,如果在指定等待时间消逝前有延迟元素则返回;否则返回null。
    方法在悲观锁的保护下,从底层的优先级队列中获取头元素。如果头元素不存在,说明不存在延迟元素,当前线程进入限时等待;如果头元素存在但未延迟到期,也说明不存在延迟元素,但当前线程的等待时间则需要具体判断。如果头元素的延迟时间大于参数等待时间,或者已存在领导者,则当前线程限时等待参数等待时间。
    在头元素的延迟时间大于参数等待时间的情况下,理论上当前线程不可能等待到头元素的延迟到期,即不可能成功移除/拿取元素。如果是这样,那为何不直接返回null而要继续等待呢?一是因为要保持"超时"形式的方法定义;二是实际上还是有可能成功移除/拿取的。例如当前线程的等待时间虽然小于头元素的剩余延迟时间,但两者十分相近,这样就可能因为系统时间片分配的原因补齐这个差距。如此,当前线程因超时而唤醒后也可以参与到头元素的竞争中,从而成功移除/拿取头元素,甚至是后续延迟到期的元素(如果后续元素紧接着延迟到期的话)。而对于领导者已存在的情况,即使头元素的延迟时间小于等于参数等待时间,也只能等待参数等待时间,因此已经有其它线程专属等待头元素了。如果头元素的延迟时间小于等于参数等待时间,并且不存在领导者,则将当前线程设置为领导者,并等待头元素的延迟时间。
    一般来说,领导者是因为超时而被唤醒的,但确实也存在被其它线程唤醒的特例。这种特例发生在头元素被其它线程移除/拿取的情况中。领导者确实有较高的概率成功移除/拿取头元素,但这并非是绝对的。在外部线程或其它限时等待线程参与竞争的情况下,无论头元素延迟过期时领导者是否因超时而唤醒,都可能无法成功的移除/拿取头元素。而如果此时领导者尚未因超时而唤醒,则其可能会被成功移除/拿取元素(一般是头元素,但也可能是后续延迟到期的元素,如果后续元素的延迟时间与头元素相同或相近)的线程唤醒,如此由于未完全的限时等待,当前线程会残留"剩余等待时间"。此时如果被唤醒的当前线程未能成功的移除/拿取元素,则其需要继续等待。继续等待的时间理论上应该是:参数等待时间 - 元素的剩余延迟时间 。但由于上轮限时等待中当前线程未能完全等待结束,因此实际继续等待时间为:参数等待时间 - 元素的剩余延迟时间 + 剩余等待时间。如果头元素存在且延时到期,说明存在延迟元素,移除/拿取优先级队列中的头元素并返回。

    /**
     * Retrieves and removes the head of this queue, waiting if necessary until an element with an expired delay is available on this
     * queue, or the specified wait time expires.
     * 检索并移除队列的头,如果必要则等待直至队列中的一个延迟到期的元素可用,或指定等待时间到期。
     *
     * @return the head of this queue, or {@code null} if the specified waiting time elapses before an element with an expired delay
     * becomes available
     * 队列的头,或如果一个延迟到期元素成为可用之前指定等待时间消逝是返回null。
     * @throws InterruptedException {@inheritDoc} 中断异常
     * @Description: 名称:轮询
     * @Description: 作用:从延迟队列(优先级队列)的队头移除并获取延迟元素。该方法是移除/拿取方法中“超时”形式的实现,
     * @Description: 当延迟队列存在延迟元素时移除/拿取并返回延迟元素;否则等待指定的等待时间,如果在指定等待时间消逝
     * @Description: 前有延迟元素则返回;否则返回null。
     * @Description: 逻辑:方法在悲观锁的保护下,从底层的优先级队列中获取头元素。如果头元素不存在,说明不存在延迟元素,
     * @Description: 当前线程进入限时等待;如果头元素存在但未延迟到期,也说明不存在延迟元素,但当前线程的等待时间则需
     * @Description: 要具体判断。如果头元素的延迟时间大于参数等待时间,或者已存在领导者,则当前线程限时等待参数等待时
     * @Description: 间。
     * @Description: 在头元素的延迟时间大于参数等待时间的情况下,理论上当前线程不可能等待到头元素的延迟到期,即不可能
     * @Description: 成功移除/拿取元素。如果是这样,那为何不直接返回null而要继续等待呢?一是因为要保持"超时"形式的方法
     * @Description: 定义;二是实际上还是有可能成功移除/拿取的。例如当前线程的等待时间虽然小于头元素的剩余延迟时间,但
     * @Description: 两者十分相近,这样就可能因为系统时间片分配的原因补齐这个差距。如此,当前线程因超时而唤醒后也可以
     * @Description: 参与到头元素的竞争中,从而成功移除/拿取头元素,甚至是后续延迟到期的元素(如果后续元素紧接着延迟到
     * @Description: 期的话)。而对于领导者已存在的情况,即使头元素的延迟时间小于等于参数等待时间,也只能等待参数等待
     * @Description: 时间,因此已经有其它线程专属等待头元素了。如果头元素的延迟时间小于等于参数等待时间,并且不存在领
     * @Description: 导者,则将当前线程设置为领导者,并等待头元素的延迟时间。
     * @Description: 一般来说,领导者是因为超时而被唤醒的,但确实也存在被其它线程唤醒的特例。这种特例发生在头元素被其
     * @Description: 它线程移除/拿取的情况中。领导者确实有较高的概率成功移除/拿取头元素,但这并非是绝对的。在外部线程
     * @Description: 或其它限时等待线程参与竞争的情况下,无论头元素延迟过期时领导者是否因超时而唤醒,都可能无法成功的
     * @Description: 移除/拿取头元素。而如果此时领导者尚未因超时而唤醒,则其可能会被成功移除/拿取元素(一般是头元素,
     * @Description: 但也可能是后续延迟到期的元素,如果后续元素的延迟时间与头元素相同或相近)的线程唤醒,如此由于未完
     * @Description: 全的限时等待,当前线程会残留"剩余等待时间"。此时如果被唤醒的当前线程未能成功的移除/拿取元素,则其
     * @Description: 需要继续等待。继续等待的时间理论上应该是:参数等待时间 - 元素的剩余延迟时间 。但由于上轮限时等待中
     * @Description: 当前线程未能完全等待结束,因此实际继续等待时间为:参数等待时间 - 元素的剩余延迟时间  + 剩余等待时间。
     * @Description: 如果头元素存在且延时到期,说明存在延迟元素,移除/拿取优先级队列中的头元素并返回。
     */
    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        // 加悲观锁。
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (; ; ) {
                // 获取优先级队列的头元素。
                E first = q.peek();
                if (first == null) {
                    // 头元素不存在,并且等待时间已结束,返回null;如果等待时间未结束,进行限时等待。
                    if (nanos <= 0)
                        return null;
                    else
                        nanos = available.awaitNanos(nanos);
                } else {
                    // 头元素存在,获取元素的剩余延迟时间。如果已到期,则移除/拿取头元素并返回。
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0)
                        return q.poll();
                    // 如果头元素存在剩余延迟时间,则判断是否还剩余等待时间。如果没有剩余则返回null
                    if (nanos <= 0)
                        return null;
                    // don't retain ref while waiting
                    // 不在等待期间保存引用

                    // 由于头元素在当前线程等待期间可能会被其它线程移除/拿取,因此如果不把当前快照遗忘,会导致该头元素无法被GC
                    // 回收。
                    first = null;
                    if (nanos < delay || leader != null)
                        // 如果线程的剩余等待时间 < 头元素的剩余延迟时间,则将当前线程限时等待剩余等待时间。这是由于当前线程的等待
                        // 时间少于头元素的剩余延迟时间,意味着当前线程不可能等待到头元素延迟到期的时候,故而只能等待剩余等待时间。
                        // 但个人理解是由于当前线程不可能获取到延迟元素(因为至少要等待到头元素的剩余延迟时间到期才有可能获取到),
                        // 因此应该可以直接返回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 && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

    public E peek() —— 窥视 —— 从延迟队列(优先级队列)的头部获取元素。该方法是检查方法中“特殊值”形式的实现,当延迟队列存在元素时返回头元素;否则返回null。注意:该方法不同于移除/拿取方法,其获取的是元素而非延迟元素,即使底层的优先级队列的头元素延迟尚未到期也会将之返回,故而只会在优先级队列真的为空时返回null。
    方法直接调用优先级队列的 peek()方法实现。

    /**
     * Retrieves, but does not remove, the head of this queue, or returns {@code null} if this queue is empty.  Unlike {@code poll}, if no
     * expired elements are available in the queue, this method returns the element that will expire next, if one exists.
     * 检索,但不移除队列的头,或者如果队列为空则返回null。不像poll()方法,如果在队列中没有到期元素可用,该方法将返回下
     * 一个将过期的元素,如果存在。
     *
     * @return the head of this queue, or {@code null} if this queue is empty 队列的头元素,或者如果为空则返回null
     * @Description: 名称:窥视
     * @Description: 作用:从延迟队列(优先级队列)的头部获取元素。该方法是检查方法中“特殊值”形式的实现,当延迟队列存
     * @Description: 在元素时返回头元素;否则返回null。注意:该方法不同于移除/拿取方法,其获取的是元素而非延迟元素,即
     * @Description: 使底层的优先级队列的头元素延迟尚未到期也会将之返回,故而只会在优先级队列真的为空时返回null。
     * @Description: 逻辑:方法直接调用优先级队列的 peek()方法实现。
     */
    public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.peek();
        } finally {
            lock.unlock();
        }
    }

    public int size() —— 大小 —— 获取延迟队列的元素总数。注意,是元素,而非延迟元素。
    方法直接调用优先级队列的size()方法实现。

    /**
     * @Description: 名称:大小
     * @Description: 作用:获取延迟队列的元素总数。注意,是元素,而非延迟元素;
     * @Description: 逻辑:方法直接调用优先级队列的 size()方法实现。
     */
    public int size() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.size();
        } finally {
            lock.unlock();
        }
    }

    public int remainingCapacity() —— 剩余容量 —— 获取延迟队列的剩余容量。由于延迟队列是无界队列,因此该方法永远返回Integer.MAX_VALUE。
    由于延迟队列是无界队列,容量理论上只受限于堆内存的大小(实际上还有int类型的限制),因此永远返回Integer.MAX_VALUE。

    /**
     * Always returns {@code Integer.MAX_VALUE} because a {@code DelayQueue} is not capacity constrained.
     * 总是返回Integer.MAX_VALUE,因为延迟队列没有容量限制。
     *
     * @return {@code Integer.MAX_VALUE}
     * @Description: 名称:剩余容量
     * @Description: 作用: 获取延迟队列的剩余容量。由于延迟队列是无界队列,因此该方法永远返回Integer.MAX_VALUE。
     * @Description: 逻辑:由于延迟队列是无界队列,容量理论上只受限于堆内存的大小(实际上还有int类型的限制),因此永远
     * @Description: 返回Integer.MAX_VALUE。
     */
    public int remainingCapacity() {
        return Integer.MAX_VALUE;
    }

    private E peekExpired() —— 窥视过期 —— 获取延迟队列的首个延迟元素。
    方法通过peek()方法获取头元素,并判断头元素是否已延迟到期。

    /**
     * Returns first element only if it is expired. Used only by drainTo.  Call only when holding lock.
     * 如果头元素已过期则返回。只在drainTo方法中使用。当持有锁时调用。
     *
     * @Description: 名称:窥视过期
     * @Description: 作用:获取延迟队列的首个延迟元素。
     * @Description: 逻辑:方法通过peek()方法获取头元素,并判断头元素是否已延迟到期。
     */
    private E peekExpired() {
        // assert lock.isHeldByCurrentThread();
        // 断言持有锁

        // 获取优先级队列的头元素,如果到期则返回,否则返回null
        E first = q.peek();
        return (first == null || first.getDelay(NANOSECONDS) > 0) ? null : first;
    }

    public int drainTo(Collection<? super E> c)—— 流失 —— 将延迟队列中的延时元素迁移到指定集中,并返回迁移的延迟元素总数。
    方法在悲观锁的保护下,获取(不移除)底层优先级队列的延时元素。并将延时元素成功的插入指定集中后,再将延时元素移除/拿取。循环执行上述操作,直至将所有的延迟元素都迁移为止。之所以要分两步执行,是为了防止延时元素在插入指定集时失败丢失的情况。如果执行移除/拿取并获取元素,如果在插入时发生异常,则该延迟元素便丢失了,即不存在与指定集中,也不存在于延迟队列中。

    /**
     * @throws UnsupportedOperationException {@inheritDoc} 不支持操作异常
     * @throws ClassCastException            {@inheritDoc} 类转换异常
     * @throws NullPointerException          {@inheritDoc} 无指针异常
     * @throws IllegalArgumentException      {@inheritDoc} 非法参数异常
     * @Description: 名称:流失
     * @Description: 作用: 将延迟队列中的延时元素迁移到指定集中,并返回迁移的延迟元素总数。
     * @Description: 逻辑:方法在悲观锁的保护下,获取(不移除)底层优先级队列的延时元素。并将延时元素成功的插入指定集
     * @Description: 中后,再将延时元素移除/拿取。循环执行上述操作,直至将所有的延迟元素都迁移为止。之所以要分两步执行,
     * @Description: 是为了防止延时元素在插入指定集时失败丢失的情况。如果执行移除/拿取并获取元素,如果在插入时发生异常,
     * @Description: 则该延迟元素便丢失了,即不存在与指定集中,也不存在于延迟队列中。
     */
    public int drainTo(Collection<? super E> c) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        // 加锁。
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            int n = 0;
            // 不断的获取延迟元素,并将之加入指定集中,随后将延迟元素移除。
            for (E e; (e = peekExpired()) != null; ) {
                // In this order, in case add() throws.
                // 按此顺序,以防add()抛出。

                // 之所以要先获取延迟元素,并将延迟元素成功插入指定集后再将之从延迟队列中移除/拿取,是为了防止延迟元素被移
                // 除/拿取后为成功插入指定集中的情况。这样会导致元素丢失,即不在延迟元素中,也不在指定集中。
                c.add(e);
                q.poll();
                ++n;
            }
            return n;
        } finally {
            lock.unlock();
        }
    }

    public int drainTo(Collection<? super E> c, int maxElements) —— 流失 —— 将延迟队列中最多指定数量的延时元素迁移到指定集中,并返回迁移的延迟元素总数。
    方法在悲观锁的保护下,获取(不移除)底层优先级队列的延时元素。并将延时元素成功的插入指定集中后,再将延时元素移除/拿取。循环执行上述操作,直至将所有的延迟元素都迁移或到达数量上限为止。

    /**
     * @throws UnsupportedOperationException {@inheritDoc} 不支持操作异常
     * @throws ClassCastException            {@inheritDoc} 类转换异常
     * @throws NullPointerException          {@inheritDoc} 无指针异常
     * @throws IllegalArgumentException      {@inheritDoc} 非法参数异常
     * @Description: 名称:流失
     * @Description: 作用:将延迟队列中最多指定数量的延时元素迁移到指定集中,并返回迁移的延迟元素总数。
     * @Description: 逻辑:方法在悲观锁的保护下,获取(不移除)底层优先级队列的延时元素。并将延时元素成功的插入指定集
     * @Description: 中后,再将延时元素移除/拿取。循环执行上述操作,直至将所有的延迟元素都迁移或到达数量上限为止。
     */
    public int drainTo(Collection<? super E> 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 {
            int n = 0;
            for (E e; n < maxElements && (e = peekExpired()) != null; ) {
                // In this order, in case add() throws.
                // 按此顺序,以防add()抛出。
                c.add(e);
                q.poll();
                ++n;
            }
            return n;
        } finally {
            lock.unlock();
        }
    }

    public void clear() —— 清除 —— 清除延迟队列中的所有元素。
    方法直接调用优先级队列的clear()方法实现。

    /**
     * Atomically removes all of the elements from this delay queue. The queue will be empty after this call returns. Elements with an
     * unexpired delay are not waited for; they are simply discarded from the queue.
     * 从延迟队列中原子性地溢出所有元素。队列将在调用返回后为空。不会等待未延迟到期的元素,只会简单的从队列中丢弃。
     *
     * @Description: 名称:清除
     * @Description: 作用:清除延迟队列中的所有元素。
     * @Description: 逻辑:方法直接调用优先级队列的clear()方法实现。
     */
    public void clear() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.clear();
        } finally {
            lock.unlock();
        }
    }

    public Object[] toArray() —— 转化数组 —— 获取一个包含延迟队列中所有元素的新数组。注意,此处获取的是元素数组,而非延迟元素数组。
    方法调用优先级队列的toArray()方法实现。

    /**
     * Returns an array containing all of the elements in this queue. The returned array elements are in no particular order.
     * 返回一个包含队列中所有元素的数组。返回的数组元素不按特定的顺序(即不按底层小顶堆的顺序)。
     * <p>
     * The returned array will be "safe" in that no references to it are maintained by this queue.  (In other words, this method must allocate
     * a new array).  The caller is thus free to modify the returned array.
     * 返回的数组是安全的,队列中没有维护对其的引用。(换句话说,该方法必须分配一个新数组)。调用者因此可以自由的修改返
     * 回的数组。
     * <p>
     * This method acts as bridge between array-based and collection-based APIs.
     * 该方法行为作为基于数组和基于集的API之间的桥梁。
     *
     * @return an array containing all of the elements in this queue  包含队列中所有元素的数组
     * @Description: 名称:转化数组
     * @Description: 作用: 获取一个包含延迟队列中所有元素的新数组。注意,此处获取的是元素数组,而非延迟元素数组。
     * @Description: 逻辑:方法调用优先级队列的toArray()方法实现。
     */
    public Object[] toArray() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.toArray();
        } finally {
            lock.unlock();
        }
    }

    public T[] toArray(T[] a) —— 转化数组 —— 获取一个包含延迟队列中所有元素的泛型数组。如果传入的参数泛型数组足够大,则承载所有的元素后返回;否则分配一个新泛型数组承载元素并返回。注意,获取的是元素数组,而非延迟元素数组。
    方法调用优先级队列的toArray(T[] a)方法实现。

    /**
     * Returns an array containing all of the elements in this queue; the runtime type of the returned array is that of the specified array.
     * The returned array elements are in no particular order. If the queue fits in the specified array, it is returned therein. Otherwise, a
     * new array is allocated with the runtime type of the specified array and the size of this queue.
     * 返回一个包含队列中所有元素的数组,返回数组的运行时类型是指定数组「的运行时类型」。返回的数组元素不按特定的顺序。如
     * 果队列符合指定数组【指队列的元素数量小于等于指定数组的长度】,则返回它【指定数组】。否则,分配一个指定数组运行时类
     * 型及队列大小的新数组。
     * <p>
     * If this queue fits in the specified array with room to spare (i.e., the array has more elements than this queue), the element in the
     * array immediately following the end of the queue is set to {@code null}.
     * 如果队列在空间放置上符合指定数组(例如,数组比队列有更多的元素),数组中的元素直接在队列结束之后设置为null。
     * <p>
     * Like the {@link #toArray()} method, this method acts as bridge between array-based and collection-based APIs.  Further, this method
     * allows precise control over the runtime type of the output array, and may, under certain circumstances, be used to save allocation costs.
     * 类似于toArray()方法,该方法行为作为基于数组及基于集的API之间沟通的桥梁。进一步的,该方法允许精确的控制输出数组的运行时
     * 类型,并且可能,在某些情况下,用于节省分配消耗。
     * <p>
     * The following code can be used to dump a delay queue into a newly allocated array of {@code Delayed}:
     * 下方代码可以倾倒一个延迟队列至一个Delayed「类型」的新分配数组。
     * <pre> {@code Delayed[] a = q.toArray(new Delayed[0]);}</pre>
     * <p>
     * Note that {@code toArray(new Object[0])} is identical in function to
     * {@code toArray()}.
     *
     * @param a the array into which the elements of the queue are to be stored, if it is big enough; otherwise, a new array of the same runtime
     *          type is allocated for this purpose
     *          如果它数组足够大,则其用于保存队列的元素;否则按计划分配一个运行时类型相同的数组。
     * @return an array containing all of the elements in this queue 一个包含队列中所有元素的数组。
     * @throws ArrayStoreException  if the runtime type of the specified array is not a supertype of the runtime type of every element in this
     *                              queue
     *                              数组保存异常:如果指定数组的运行时类型不是队列中每个元素的超类
     * @throws NullPointerException if the specified array is null 如果指定数组为null
     * @Description: 名称:转化数组
     * @Description: 作用: 获取一个包含延迟队列中所有元素的泛型数组。如果传入的参数泛型数组足够大,则承载所有的元素后返回;否则
     * @Description: 分配一个新泛型数组承载元素并返回。注意,获取的是元素数组,而非延迟元素数组。
     * @Description: 逻辑:方法调用优先级队列的toArray(T[] a)方法实现。
     */
    public <T> T[] toArray(T[] a) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.toArray(a);
        } finally {
            lock.unlock();
        }
    }

    public boolean remove(Object o) —— 移除 —— 移除延迟队列中指定元素的单例。
    方法调用优先级队列的remove方法实现。

    /**
     * Removes a single instance of the specified element from this queue, if it is present, whether or not it has expired.
     * 从队列中移除指定元素的单例,如果它是存在的,不论它是否到期。
     *
     * @Description: 名称:移除
     * @Description: 作用:移除延迟队列中指定元素的单例。
     * @Description: 逻辑:方法调用优先级队列的remove方法实现。
     */
    public boolean remove(Object o) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.remove(o);
        } finally {
            lock.unlock();
        }
    }

    void removeEQ(Object o) —— 移除元素 —— 移除延迟队列中指定元素的单例。
    方法调用优先级队列的remove方法实现。

    /**
     * Identity-based version for use in Itr.remove
     * 基于身份的版本在迭代移除中使用
     *
     * @Description: 名称:移除元素
     * @Description: 作用:移除延迟队列中指定元素的单例。
     * @Description: 逻辑:方法调用优先级队列的remove方法实现。
     */
    void removeEQ(Object o) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 迭代底层优先级队列中的元素,如果相同,则调用迭代器的迭代方法将移除。
            for (Iterator<E> it = q.iterator(); it.hasNext(); ) {
                if (o == it.next()) {
                    it.remove();
                    break;
                }
            }
        } finally {
            lock.unlock();
        }
    }

    public Iterator iterator() —— 迭代器 —— 获取一个延迟队列的迭代器。
    方法直接调用toArray()方法获得一份所有元素的快照保存在迭代器中用于遍历。

    /**
     * Returns an iterator over all the elements (both expired and unexpired) in this queue. The iterator does not return the
     * elements in any particular order.
     * 返回迭代队列中所有元素(到期和未到期)的迭代器。该迭代器返回的元素不按特定的顺序。
     * <p>
     * The returned iterator is <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
     * 返回的迭代器是弱一致性的。
     *
     * @return an iterator over the elements in this queue 遍历队列中元素的迭代器
     * @Description: 名称:迭代器
     * @Description: 作用:获取一个延迟队列的迭代器。
     * @Description: 逻辑:方法直接调用toArray()方法获得一份所有元素的快照保存在迭代器中用于遍历。
     */
    public Iterator<E> iterator() {
        return new Itr(toArray());
    }

二 Itr类源码及机制详解


 类

    /**
     * Snapshot iterator that works off copy of underlying q array.
     * 快照迭代器,该迭代器工作于潜在的q数组的副本。
     */
    private class Itr implements Iterator<E> {
    ...
}

 字段

    array(数组) —— 持有延迟队列元素数组的快照。

        /**
         * Array of all elements
         * 所有元素的数组
         *
         * @Description: 名称:数组
         * @Description: 作用:持有延迟队列元素数组的快照。
         * @Description: 逻辑:~
         */
        final Object[] array;

    cursor(游标) —— 记录下个元素在数组中的索引。

        /**
         * index of next element to return
         * 下个元素的索引
         *
         * @Description: 名称:游标
         * @Description: 作用:记录下个元素在数组中的索引。
         * @Description: 逻辑:~
         */
        int cursor;

    currentElement(当前元素) —— 用于持有当前节点中容纳的元素。由于节点可能会被移除/拿取(包括中途移除),这种情况下节点都会被转化空节点,因此元素需要额外保存。

/**
 * 当前元素:即当前节点对应的元素,由于节点被出队/移除后其内部的元素会被置null,因此还需要额外保存;
 */
private E currentElement;

    lastRet(上个索引) —— 记录上个元素在数组中的索引。

        /**
         * index of last element, or -1 if no such
         * 上个元素的索引,如果没有则为1
         *
         * @Description: 名称:上个索引
         * @Description: 作用:记录上个元素在数组中的索引。
         * @Description: 逻辑:~
         */
        int lastRet;

 构造方法

    Itr(Object[] array)—— 初始化延迟队列的迭代器,保存元素数组。

        /**
         * @Description: 名称:~
         * @Description: 作用:初始化延迟队列的迭代器,保存元素数组。
         * @Description: 逻辑:~
         */
        Itr(Object[] array) {
            lastRet = -1;
            this.array = array;
        }

 方法

    public boolean hasNext() —— 有下个 —— 判断是否存在下个可迭代的元素。如果存在返回true;否则返回false。

        /**
         * @Description: 名称:有下个
         * @Description: 作用:判断是否存在下个可迭代的元素。如果存在返回true;否则返回false。
         * @Description: 逻辑:方法判断游标的大小是否小于数组的长度。
         */
        public boolean hasNext() {
            return cursor < array.length;
        }

    public boolean hasNext() —— 有下个 —— 判断是否存在下个可迭代的元素。如果存在返回true;否则返回false。
    方法通过游标获取下个迭代的元素,并前进游标及上个索引。

        /**
         * @Description: 名称:下个
         * @Description: 作用:获取下个迭代元素。
         * @Description: 逻辑:方法通过游标获取下个迭代的元素,并前进游标及上个索引。
         */
        @SuppressWarnings("unchecked")
        public E next() {
            if (cursor >= array.length)
                throw new NoSuchElementException();
            lastRet = cursor;
            return (E) array[cursor++];
        }

    public E next() —— 下个 —— 获取下个迭代元素。
    方法通过游标获取下个迭代的元素,并前进游标及上个索引。

        /**
         * @Description: 名称:下个
         * @Description: 作用:获取下个迭代元素。
         * @Description: 逻辑:方法通过游标获取下个迭代的元素,并前进游标及上个索引。
         */
        @SuppressWarnings("unchecked")
        public E next() {
            if (cursor >= array.length)
                throw new NoSuchElementException();
            lastRet = cursor;
            return (E) array[cursor++];
        }

    public E next() —— 移除 —— 移除上个迭代元素。
    方法通过调用removeEQ(Object o)方法实现。

        /**
         * @Description: 名称:移除
         * @Description: 作用:移除上个迭代元素。
         * @Description: 逻辑:方法通过调用removeEQ(Object o)方法实现。
         */
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            removeEQ(array[lastRet]);
            lastRet = -1;
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

说淑人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值