DelayQueue源码解析

908 阅读1分钟

概念

DelayQueue是BlockingQueue的实现类,在原本的基础上增加了延迟等待的操作,底层用到了PriorityQueue和Leader-Follower模式。

Delayed

DelayQueue中存储的对象必须是Delayed,赋予了延迟操作的能力,Delayed继承Comparable,因此也要重写compareTo方法


public interface Delayed extends Comparable<Delayed> {

    /**
     * 
     *
     * @param unit 时间单位
     * @return 返回等待的时间
     */
    long getDelay(TimeUnit unit);
}

put方法

  public void put(E e) {
        offer(e);
    }
    
 private final PriorityQueue<E> q = new PriorityQueue<E>(); //优先级队列,按照延迟最小排序   
 public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.offer(e);
            if (q.peek() == e) { //如果新加入的是最小的延迟时间,就重新唤醒一个作为leader去处理
                leader = null;
                available.signal();
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

take方法

public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                E first = q.peek(); //获取首位数据
                if (first == null) //为null就等待
                    available.await();
                else { 
                    //不为null就获取延迟时间
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0) //延迟时间<=0 就poll
                        return q.poll();
                    first = null; 
                    if (leader != null) //已经存在leader就等待即可
                        available.await();
                    else {
                        //不存在leader,就用当前线程作为leader
                        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();
        }
    }

总结

DelayQueue使用PriorityQueue进行延迟时间排序,当不存在leader时,会使用当前线程作为leader,如果存在,判断时间是否新加入的时间更少,如果是就唤醒一个新的follower成为leader去处理。