当前位置: 代码迷 >> 综合 >> java源码解析-阻塞队列-DelayQueue
  详细解决方案

java源码解析-阻塞队列-DelayQueue

热度:83   发布时间:2024-02-24 20:05:11.0

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种情况

  1.  当堆顶元素不存在时,线程阻塞在condtion,等待添加线程唤醒
  2.  当堆顶元素存在,且已经过期满足可用条件,直接弹出使用,
  3.  堆顶元素delay>0 未达到使用条件,且leader不为null,表示前面已经有线程在等待使用堆顶元素,则直接阻

  4. 堆顶元素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 其他操作

        其他操作,诸如获取队列长度的方法都比较简单