DelayQueue源码解析
DelayQueue并发队列是一个无界阻塞延迟队列,队列中的每个元素都有个过期时间,当从队列获取元素时,只有过期元素才会出队列。队列头元素时最快要过期的元素。
DelayQueue使用PriorityQueue存放数据,使用ReentrantLock实现线程同步。
另外,队列里面的元素要实现Delayed接口,一个是获取当前剩余时间的接口,一个是比较的接口。
类图
DelayQueue的类图如下所示:
DelayQueue实现了BlockingQueue接口和继承了AbstractQueue类。
1 | public class DelayQueue<E extends Delayed> extends AbstractQueue<E> |
BlockingQueue接口只是定义了一些阻塞队列的公共方法,如下:
1 | public interface BlockingQueue<E> extends Queue<E> { |
AbstractQueue也实现了Queue接口,还提供了某些方法的默认实现
1 | // 从这可以发现,Add方法,其实就是调用的offer方法 |
DelayQueue中的元素需要实现Delayed接口
1 | public interface Delayed extends Comparable<Delayed> { |
主要属性
1 | // 并发控制锁 |
主要方法
无参构造函数
1 | /** |
创建一个空的延时阻塞队列
有参构造函数-指定集合
调用addAll方法
1 | /** |
addAll
遍历集合c,调用add方法,将集合c中的每个元素加入队列之中。如果在添加的过程中集合c发生了改变,那么addAll的行为就是不可预知的。
1 | public boolean addAll(Collection<? extends E> c) { |
add方法
调用了offer方法
1 | /** |
offer方法
- 获取锁
- 调用优先级队列的offer方法,入队
- 确认队首元素是否为新增元素,是的话,设置leader为null,并且唤醒一个取线程
leader的作用,要结合take方法来看,
1 | /** |
put方法
基于这个阻塞队列是无界的,这个方法永远不会阻塞
1 | /** |
poll方法
获取队首元素并从队列中删除队首元素。如果在过期时间之前没有元素的话,返回null
1 | /** |
put方法
内部调用offer方法
1 | /** |
take方法
从队列中获取并删除队首元素,如果队首元素还未过期,则阻塞当前线程,直到该元素过期为止。
1 | /** |
Leader线程时等待头部队列元素的指定线程。Leader-Follower模式的这种变化用于最小化不必要的定时等待:
- 当一个线程称为leader时,其会定时等待下一个delay元素过期,但是其他线程会无限期等待
- 当从take/poll返回之前,leader线程必须signal其他等待线程,除非在此期间有线程成为了新的leader
- 每当队列头部元素被更早到期的元素替换时,leader被置为null,offer里面q.peek == e时,会将leader置为null,此时触发signal,重新竞选leader。所以定时等待线程必须要处理失去leader时情况。
peek方法
1 | public E peek() { |
size方法
1 | public int size() { |
remainingCapacity方法
队列无界,因此返回最大的Integer.MAX_VALUE
1 | /** |
remove方法
从队列中删除指定的元素,有返回true,否则返回false
调用优先级队列的接口
1 | /** |