类的描述
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E>
一种延迟元素的无界阻塞队列,其中一个元素只有在其延迟过期时才能被占用。队列的头是延迟过期时间在过去最长的延迟元素。如果没有延迟过期,则没有head,poll将返回null。当元素的getDelay(TimeUnit.NANOSECONDS)方法返回小于或等于零的值时,将发生过期。即使无法使用take或poll删除未过期的元素,它们也会被视为正常元素。例如,size方法返回过期和未过期元素的计数。此队列不允许空元素。
这个类和它的迭代器实现所有的可选方法的Collection和Iterator接口。方法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 是用来实现 等待获取元素功能的(最上面的猜想是错误的)