JDK1.8版本
特点
1.无界队列
2.延迟队列
3.线程安全
实现
1.延迟队列中的元素,需要是实现Delayed接口的
2.使用优先级队列(PriorityQueue)作为容器
3.可重入锁ReentrantLock保证线程安全
4.Thread leader 使用Leader-Follower模式来减少线程间的等待
5.Condition available,相关的锁条件
DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E>{//延迟队列中的元素,需要是实现Delayed接口的
private final PriorityQueue<E> q = new PriorityQueue<E>(); //使用优先级队列(PriorityQueue)作为容器
private final transient ReentrantLock lock = new ReentrantLock();//可重入锁ReentrantLock保证线程安全
private Thread leader = null;//使用Leader-Follower模式来减少线程间的等待
private final Condition available = lock.newCondition();//相关的锁条件
....//后面逐一介绍
}
主要方法
1.入队方法,add(E e),offer(E e),put(E e),offer(E e, long timeout, TimeUnit unit)
1.1 add(E e)
直接使用内部的offer(E e)方法,其他没什么好讲的
public boolean add(E e) {
return offer(e);
}
1.2 put(E e)
直接使用内部的offer(E e)方法,因为是无界队列,所以无需阻塞
public void put(E e) {
offer(e);
}
1.3 offer(E e, long timeout, TimeUnit unit)
直接使用内部的offer(E e)方法,因为是无界队列,所以无需阻塞
public boolean offer(E e, long timeout, TimeUnit unit) {
return offer(e);
}
1.4 offer(E e)
使用优先级队列的入队方法进行入队操作;如果队首元素是当前元素,那么把线程置空,并通知阻塞的出队线程
public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock();//获取锁
try {
q.offer(e);//使用优先级队列的入队方法,详情请参考另外一篇文档
if (q.peek() == e) {//如果队首元素是当前元素,那么把线程置空,并通知阻塞的出队线程
leader = null;
available.signal();
}
return true;
} finally {
lock.unlock();
}
}
2.出队方法 poll(),take(),poll(long timeout, TimeUnit unit),peek()
2.1 poll()
如果队首元素为空或者元素延迟时间没到,那么返回null 否则 出队
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock(); //获取锁
try {
E first = q.peek(); //获取队首元素
if (first == null || first.getDelay(NANOSECONDS) > 0) //如果队首元素为空或者元素延迟时间没到,那么返回null
return null;
else
return q.poll();//否则出队
} finally {
lock.unlock();//释放锁
}
}
2.2 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) //延迟时间已到,直接出队
return q.poll();
first = null; // 防止内存泄露,设想一下多个线程的时候
if (leader != null)//判断是否有其他的线程在等待,有的话直接把该线程直接进入等待(想下leader-Follower模式)
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)//处理线程为空,切队首元素不为空,那么通知唤醒等待的线程
available.signal();
lock.unlock();//释放锁
}
}
2.3 poll(long timeout, TimeUnit unit)
在规定的时间内出队,有元素就返回队首,没有就返回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)//且等待时间已到,则返回null
return null;
else //否则等待超时
nanos = available.awaitNanos(nanos);
} else { //其他的类似take()
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)
return q.poll();
if (nanos <= 0)
return null;
first = null; // don't retain ref while waiting
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();
}
}
2.4 peek()
出队,但不会移除队首元素,即使该元素没有过期
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();//获取锁
try {
return q.peek();//返回队首
} finally {
lock.unlock();
}
}