JAVA源码学习之集合-DelayQueue

类的描述

public class DelayQueue<E extends Delayed>
extends AbstractQueue<E>
implements BlockingQueue<E>

一种延迟元素的无界阻塞队列,其中一个元素只有在其延迟过期时才能被占用。队列的头是延迟过期时间在过去最长的延迟元素。如果没有延迟过期,则没有head,poll将返回null。当元素的getDelay(TimeUnit.NANOSECONDS)方法返回小于或等于零的值时,将发生过期。即使无法使用take或poll删除未过期的元素,它们也会被视为正常元素。例如,size方法返回过期和未过期元素的计数。此队列不允许空元素。

这个类和它的迭代器实现所有的可选方法的CollectionIterator接口。方法iterator()提供的迭代器不能保证导线的DelayQueue元素在任何特定的顺序。

常量、变量、静态内部类

 private final transient ReentrantLock lock = new ReentrantLock();
    private final PriorityQueue<E> q = new PriorityQueue<E>();
     
    /** 指定在队列头部等待元素的线程。这是先导-跟随模式的变体 
      *(http://www.cs.wustl.edu/~schmidt/POSA/POSA2/)用于最小化不必要的定时等待。当一个线程成 
      *为领导者时,它只等待下一个延迟过去,而其他线程则无限期地等待。在从take()或poll(…)返回之 
      *前,前导线程必须向其他线程发送信号,除非其他线程在此期间成为领导者。每当队列的头被一个过期时 
      *间较早的元素替换时,leader字段就会被重置为null而失效,并且一些等待的线程(不一定是当前的 
      *leader)会收到信号。因此,等待线程必须做好准备,在等待过程中获得并失去领导力。
      */
    private Thread leader = null;

    /**
     * 当一个较新的元素在队列的前端变得可用,或者一个新线程可能需要成为队列的领导者时,发出的状态信 
     *号
     */
    private final Condition available = lock.newCondition();

根据上面的类的描述和相关变量,猜想

DelayQueue是通过PriorityQueue来存储元素, 通过E元素本身的Comparable比较方法来进行排序的

通过ReentrantLock实现阻塞的

通过 线程leader和Contiton available来实现过期的

构造方法

public DelayQueue() {}

public DelayQueue(Collection<? extends E> c) {
        this.addAll(c);
    }

 // 父类AbstractQueue的addAll
 public boolean addAll(Collection<? extends E> c) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        boolean modified = false;
        for (E e : c)
            if (add(e)) //调用本地的add
                modified = true;
        return modified;
    }

队列中常用的方法

add

 public boolean add(E e) {
        return offer(e);
    }

offer

 public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.offer(e); //优先级堆offer
            if (q.peek() == e) { //如果为第一个元素
                leader = null;
                available.signal(); //队列有元素通知
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

poll

  public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E first = q.peek();
             //判断当前元素剩余延迟时间是否>0,大于 0返回null, 
            if (first == null || first.getDelay(NANOSECONDS) > 0) 
                return null;
            else
                return q.poll();
        } finally {
            lock.unlock();
        }
    }

/** 检索并删除此队列的头,如有必要,等待此队列上具有过期延迟的元素可用,或指定的等待时间过期。
  *  返回:此队列的头,如果在具有过期延迟的元素可用之前经过指定的等待时间,则为null
  */

 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) { //第一个元素不存在
                    if (nanos <= 0)  // 如果等待时间 < 0 , 直接返回null
                        return null;
                    else
                       //将当前前程放入等待队列,等待时间为nanos, 如果超过nacos, 报错
                        nanos = available.awaitNanos(nanos);
                } else {
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0) //如果延迟时间为《= 返回元素
                        return q.poll();
                    if (nanos <= 0) // 如果等等时间为0 返回null
                        return null;
                    first = null; // don't retain ref while waiting
                    //等待时间 < 延迟时间或者 leader != null
                    // //将当前前程放入等待队列,等待时间为nanos, 如果超过nacos, 报错
                    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 && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

task

/** 检索并删除此队列的头,如有必要,等待此队列上具有过期延迟的元素可用 */
public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                E first = q.peek();
                if (first == null) // 如果为0
                    available.await(); //将当前前程放到等待队列
                else {
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0)
                        return q.poll();
                    first = null; // don't retain ref while waiting
                    if (leader != null) // 如果线程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 && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

peek

public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.peek();
        } finally {
            lock.unlock();
        }
    }

  //元素过期才返回元素
  private E peekExpired() {
        // assert lock.isHeldByCurrentThread();
        E first = q.peek();
        return (first == null || first.getDelay(NANOSECONDS) > 0) ?
            null : first;
    }

element

//AbstractQueue的element
  public E element() {
        E x = peek();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

结论:

1, DelayQueue是通过PriorityQueue队列来存储元素的,使用Delay元素的本身的比较方法进行排序的

2. 通过ReentrantLock实现阻塞的

3. 通过Delay元素本身方法 long getDelay(TimeUnit unit); 来实现延迟的

4.  线程leader和Contiton available 是用来实现 等待获取元素功能的(最上面的猜想是错误的)

上一章                                                                                                                             下一章

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值