1.继承体系
2.源码解析
2.1 属性分析
// 内部锁,用于控制同步操作
private final transient ReentrantLock lock = new ReentrantLock();// 真正存储数据的结构,使用了一个优先队列,优先条件为加入执行时间 private final PriorityQueue<E> q = new PriorityQueue<E>();// private Thread leader = null;// 条件队列,标识当前队列是否有节点可用
private final Condition available = lock.newCondition();
2.2 添加元素
添加元素是非阻塞的,一共有4个添加方法,都是对offer方法的封装
public boolean add(E e) {return offer(e);}public void put(E e) {offer(e);}public boolean offer(E e, long timeout, TimeUnit unit) {return offer(e);}public boolean offer(E e) {// 加锁final ReentrantLock lock = this.lock;lock.lock();try {// 将元素加入优先队列中q.offer(e);// 如果当前元素为优先队列的头,则将leader设置为null,并唤醒等待队列中的元素来处理if (q.peek() == e) {leader = null;available.signal();}return true;// 解锁} finally {lock.unlock();}}
2.2 获取元素
获取元素分为非阻塞式获取,和阻塞式获取
2.2.1 非阻塞式获取poll
当堆顶元素可用时返回堆顶元素,不存在或者不可用时返回null
public E poll() {final ReentrantLock lock = this.lock;lock.lock();try {// 获取堆顶元素E first = q.peek();// 当堆顶元素不可用时,立即返回nullif (first == null || first.getDelay(NANOSECONDS) > 0)return null;// 当堆顶元素可用时,弹出堆顶元素elsereturn q.poll();} finally {lock.unlock();}}
2.2.2 阻塞式获取take
阻塞式获取分为4种情况
- 当堆顶元素不存在时,线程阻塞在condtion,等待添加线程唤醒
- 当堆顶元素存在,且已经过期满足可用条件,直接弹出使用,
-
堆顶元素delay>0 未达到使用条件,且leader不为null,表示前面已经有线程在等待使用堆顶元素,则直接阻
-
堆顶元素delay>0 未达到使用条件,且leader为null,则当前线程为请求使用堆顶元素的第一个线程,将自己阻塞delay时间后,
满足情况2,拿到堆顶元素使用
public E take() throws InterruptedException {final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {// 自旋for (;;) {// 获取优先队列堆顶元素E first = q.peek();// 条件1:如果堆顶元素为null,表示当前队列没有可以元素,阻塞等待,等待添加线程唤醒if (first == null)available.await();///条件2:当前堆顶元素不为null,需要进一步根据延时时间进行处理else {// 条件2.1: 如果delay<0 表示当前堆顶元素已经过期,直接弹出使用long delay = first.getDelay(NANOSECONDS);if (delay <= 0)return q.poll();first = null; // don't retain ref while waiting// 条件2.2:堆顶元素delay>0 未达到使用条件,且leader不为null,表示前面已经有线程在等待使用,则直接阻塞if (leader != null)available.await();// 条件2.2:堆顶元素delay>0 未达到使用条件,且当前线程为第一个请求堆顶元素的线程,则// ,将leader设置为空,其他等待线程可以来竞争下一个堆顶元素的使用权//else {// 将leader设为当前线程Thread thisThread = Thread.currentThread();leader = thisThread;try {//阻塞等待delay时间,被唤醒后,堆顶元素available.awaitNanos(delay);} finally {if (leader == thisThread)leader = null;}}}}} finally {if (leader == null && q.peek() != null)available.signal();lock.unlock();}}
2.3 其他操作
其他操作,诸如获取队列长度的方法都比较简单