public interface Delayed extends Comparable<Delayed> {
/**
* Returns the remaining delay associated with this object, in the
* given time unit.
*
* @param unit the time unit
* @return the remaining delay; zero or negative values indicate
* that the delay has already elapsed
*/
long getDelay(TimeUnit unit);
}
Delayed接口是用来标记那些应该在给定延迟时间之后执行的对象,它定义了一个long getDelay(TimeUnit unit)方法,该方法返回与此
对象相关的的剩余时间。同时实现该接口的对象必须定义一个compareTo 方法,该方法提供与此接口的getDelay 方法一致的排序。
4.3 核心属性
/** 可重入锁 */
private final transient ReentrantLock lock = new ReentrantLock();
/** 支持优先级的BlockingQueue */
private final PriorityQueue<E> q = new PriorityQueue<E>();
/** 用于优化阻塞 */
private Thread leader = null;
/** Condition */
private final Condition available = lock.newCondition();
PS:看了DelayQueue的内部结构就对上面几个关键点一目了然了,但是这里有一点需要注意,DelayQueue的元素都必须继承Delayed接口。
同时也可以从这里初步理清楚DelayQueue内部实现的机制了:以支持优先级无界队列的PriorityQueue作为一个容器,容器里面的元素都
应该实现Delayed接口,在每次往优先级队列中添加元素时以元素的过期时间作为排序条件,最先过期的元素放在优先级最高。
4.4 入列操作
offer:队尾添加,队满时返回false,有重载方法支持自定义超时
public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 向 PriorityQueue中插入元素,其实是使用内部的优先级队列作为容器来保存元素
q.offer(e);
// 如果当前元素是队首元素(优先级最高),leader设置为空,唤醒所有等待线程
if (q.peek() == e) {
leader = null;
available.signal();
}
// 无界队列,永远返回true
return true;
} finally {
lock.unlock();
}
}
java.util.PriorityQueue.offer
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e);
return true;
}
java.util.PriorityQueue.siftUp
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
到这里我们明白了,其实内部的优点级队列和PriorityBlockingQueue很类似,也是添加通过维持小堆的特性来保证优先级。
在PriorityQueue里面是可以兼容包含比较器和不包含比较器2中情况的,因为保存进DelayQueue的元素是必须实现Delay
这个接口的,因此这样类本身就可以用来做比较,并且比较的就是剩余的到期时间
4.5 出列操作
take:
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
E first = q.peek(); // 对首元素
if (first == null)
available.await(); // 对首为空,阻塞,等待offer()操作唤醒
else {
long delay = first.getDelay(NANOSECONDS); // 获取对首元素的超时时间
if (delay <= 0) // <=0 表示已过期,出队,return
return q.poll();
first = null; // don't retain ref while waiting
if (leader != null) // leader != null 证明有其他线程在操作,阻塞
available.await();
else {
// 否则将leader 设置为当前线程,独占
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
// 超时阻塞
available.awaitNanos(delay);
} finally {
// 释放leader
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
// 唤醒阻塞线程
if (leader == null && q.peek() != null)
available.signal();
lock.unlock();
}
}