延迟队列在java并发包中 其源码来说相对较简单,下面就让我们来分析一下延迟队列的实现,以下是基于jdk1.8实现的DelayQueue的主干代码
package java.util.concurrent; import java.util.concurrent.locks.*; import java.util.*; public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E> { //锁 private transient final ReentrantLock lock = new ReentrantLock(); //优先级队列 其目的是使最小执行的位于队列队首 private final PriorityQueue<E> q = new PriorityQueue<E>(); //leader 作用我在最后会解释 private Thread leader = null; //判断条件,不明白的去百度下lock锁中condition的用法, private final Condition available = lock.newCondition(); public DelayQueue() {} public DelayQueue(Collection<? extends E> c) { this.addAll(c); } public boolean add(E e) { return offer(e); } public boolean offer(E e) { final ReentrantLock lock = this.lock; //加锁 lock.lock(); try { q.offer(e); //入队列 //相等说明,加入的优先级更高,需要重新设置leader 这部分看不懂,请先看完下面回过头来看 if (q.peek() == e) { leader = null; //leader置为空, available.signal(); //唤醒等待的线程 } return true; } finally { lock.unlock(); } } public void put(E e) { offer(e); } public boolean offer(E e, long timeout, TimeUnit unit) { return offer(e); } //出队列 public E poll() { final ReentrantLock lock = this.lock; lock.lock(); try { E first = q.peek(); //得到对头元素 //为空,或者还没到执行时间 返回空 if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)//为空 return null; else return q.poll(); //否则 取出对头元素 } finally { lock.unlock(); } } /** * 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} */ 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(TimeUnit.NANOSECONDS); if (delay <= 0) //小于或等于0 说明到期 return q.poll(); //返回 else if (leader != null) //不为空 available.await(); //等待 else { //为空进入这里,将当前线程赋值给leader Thread thisThread = Thread.currentThread(); leader = thisThread; try { available.awaitNanos(delay); //等待delay时间后,重新竞争锁 } finally { if (leader == thisThread) //等于当前线程,有可能leader改变 //如新加入的元素位于队首就有可能 leader = null; //置为空 } } } } } finally { if (leader == null && q.peek() != null) available.signal(); // lock.unlock(); } } 这里解释下leader的作用,leader表示正在等待队首任务的线程,因为任务有一个线程执行过就够了,在多线程的环境下,如果没有leader,多个线程并发执行后,假设同时调用 available.awaitNanos(delay)后, 导致同一时间后同时苏醒,多个线程并发竞争锁,加剧了锁的竞争和cpu的开销,为此这里使用leader做个优化,表明队首任务已近有线程在等待,其他线程直接await()无限等待,直到被唤醒即可。即前面在offer时如果加入后的元素位于队首,leader需要置空,并唤醒线程 /** * 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 <tt>null</tt> if the * specified waiting time elapses before an element with * an expired delay becomes available * @throws InterruptedException {@inheritDoc} */ //与take差不多,只不过带一个超时时间,大部分是一样的这里就不做解释了 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) return null; else nanos = available.awaitNanos(nanos); } else { long delay = first.getDelay(TimeUnit.NANOSECONDS); if (delay <= 0) return q.poll(); if (nanos <= 0) return null; 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(); } } /** * Retrieves, but does not remove, the head of this queue, or * returns <tt>null</tt> if this queue is empty. Unlike * <tt>poll</tt>, if no expired elements are available in the queue, * this method returns the element that will expire next, * if one exists. * * @return the head of this queue, or <tt>null</tt> if this * queue is empty. */ public E peek() { final ReentrantLock lock = this.lock; lock.lock(); try { return q.peek(); } finally { lock.unlock(); } } public int size() { final ReentrantLock lock = this.lock; lock.lock(); try { return q.size(); } finally { lock.unlock(); } } /** * 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. */ public void clear() { final ReentrantLock lock = this.lock; lock.lock(); try { q.clear(); } finally { lock.unlock(); } } /** * Removes a single instance of the specified element from this * queue, if it is present, whether or not it has expired. */ public boolean remove(Object o) { final ReentrantLock lock = this.lock; lock.lock(); try { return q.remove(o); } finally { lock.unlock(); } } }