点击此处去Gitee上Clone源码下来在IDE上看效果更佳
package java.util.concurrent;
import java.util.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
/**
* 一种由延迟元素组成的无界阻塞队列,其中一个元素只有在其延迟过期时才能被获取。
* 队列的头是延迟元素,其延迟在过去过期最长。如果没有延迟过期,则没有head,poll将返回null,take则会阻塞。
* 不允许空元素。
* 队列中元素必须实现Delayed接口。
*/
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E> {
private final transient ReentrantLock lock = new ReentrantLock();
//底层组合了PriorityQueue,PriorityQueue是一个基于堆排序的队列。
private final PriorityQueue<E> q = new PriorityQueue<E>();
/**
* 指定在队列头等待的线程,以减少不必要的定时等待。
* 当一个线程成为引导线程时,它只等待下一个延迟过去,而其他线程则无限期地等待。
* 在从take()或poll()返回之前,前导线程必须向其他线程发出信号,除非其他线程在此期间成为leader。
* 每当队列的头被替换为新元素时,leader字段将通过重置为null而失效,并向某些等待线程(但不一定是当前的leader)发出信号。
* 因此,等待线程必须做好准备,以便在等待期间获得和失去领导权。
*/
private Thread leader = null;
/**
* 用于存放阻塞的take操作线程
*/
private final Condition available = lock.newCondition();
/*构造函数*/
public DelayQueue() {
}
public DelayQueue(Collection<? extends E> c) {
this.addAll(c);
}
/*入队相关方法,入队不存在阻塞情况*/
public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
q.offer(e);//使用底层的PriorityQueue入队
if (q.peek() == e) {//如果此节点刚好是头节点,则唤醒条件队列等待take的线程
leader = null;
available.signal();
}
return true;
} finally {
lock.unlock();
}
}
public boolean add(E e) {
return offer(e);
}
//只是重写接口的方法,实际上不需要实现
public boolean offer(E e, long timeout, TimeUnit unit) {
return offer(e);
}
public void put(E e) {
offer(e);
}
/**
* 返回头节点,如果头节点为空或者头节点没有过期,就返回,否则返回null
*/
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
E first = q.peek();
//判断头节点是否为空和头节点是否过期
if (first == null || first.getDelay(NANOSECONDS) > 0)
return null;
else
return q.poll();
} 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)
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)//过期则说明可以poll
return q.poll();
first = null; // 等待时不要保留引用,为了方便GC
//存在leader的话直接进入等待状态
if (leader != null)
available.await();
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;//把当前线程设置为leader
try {
available.awaitNanos(delay);//等待头节点过期
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
if (leader == null && q.peek() != null)//头节点不为空,leader不存在,则新唤醒一个等待take的线程。
available.signal();
lock.unlock();
}
}
/**
* 带有超时等待的poll,道理都差不多
*/
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(NANOSECONDS);
if (delay <= 0)
return q.poll();
if (nanos <= 0)
return null;
first = 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();
}
}
/**
* 看下头节点
*/
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();
}
}
/**
* 返回过期的头节点
*/
private E peekExpired() {
// assert lock.isHeldByCurrentThread();
E first = q.peek();
return (first == null || first.getDelay(NANOSECONDS) > 0) ?
null : first;
}
/**
* 把队列中所有过期的元素转移到c中
*/
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; ) {
c.add(e); // In this order, in case add() throws.
q.poll();
++n;
}
return n;
} finally {
lock.unlock();
}
}
/**
* 把队列中不超过maxElements的过期的元素转移到c中
*/
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; ) {
c.add(e); // In this order, in case add() throws.
q.poll();
++n;
}
return n;
} finally {
lock.unlock();
}
}
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
q.clear();
} finally {
lock.unlock();
}
}
public int remainingCapacity() {
return Integer.MAX_VALUE;
}
public Object[] toArray() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return q.toArray();
} finally {
lock.unlock();
}
}
public <T> T[] toArray(T[] a) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return q.toArray(a);
} 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();
}
}
/**
* Identity-based version for use in Itr.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<E> iterator() {
return new Itr(toArray());
}
/**
* Snapshot iterator that works off copy of underlying q array.
*/
private class Itr implements Iterator<E> {
final Object[] array; // Array of all elements
int cursor; // index of next element to return
int lastRet; // index of last element, or -1 if no such
Itr(Object[] array) {
lastRet = -1;
this.array = array;
}
public boolean hasNext() {
return cursor < array.length;
}
@SuppressWarnings("unchecked")
public E next() {
if (cursor >= array.length)
throw new NoSuchElementException();
lastRet = cursor;
return (E) array[cursor++];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
removeEQ(array[lastRet]);
lastRet = -1;
}
}
}