【JUC源码解析】DelayQueue
简介
基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首。只有过期的元素才能出队,在此之前,线程等待。
源码解析
属性
1 private final transient ReentrantLock lock = new ReentrantLock(); // 可重入锁 2 private final PriorityQueue<E> q = new PriorityQueue<E>(); // 优先级队列 3 private Thread leader = null; // 领导者线程,成为领导者的线程,只会等待队首元素的delay时间,其他线程会一直等待,直到有线程唤醒它,一直等待的这些线程会伴随着一个个元素的出队相继成为leader,同一时刻,只有一个线程作为领导者等待一个delay时间 4 private final Condition available = lock.newCondition(); // 条件队列,阻塞的线程会被压入条件队列,等待被唤醒
构造方法
1 public DelayQueue() { 2 } 3 4 public DelayQueue(Collection<? extends E> c) { 5 this.addAll(c); 6 }
关键方法
offer(E e)
1 public boolean offer(E e) { 2 final ReentrantLock lock = this.lock; 3 lock.lock(); // 获取锁 4 try { 5 q.offer(e); // 入队 6 if (q.peek() == e) { // 队首元素更新为新加入的元素 7 leader = null; // 上一个领导者线程同其他线程一样被同等对待(等着被唤醒),重新抢占leader,其实不必抢占(因为只有一个线程被唤醒),只不过leader线程等待的delay需要更新(新的队首元素的delay值) 8 available.signal(); // 只会唤醒Condition队列的队首线程 9 } 10 return true; 11 } finally { 12 lock.unlock(); // 释放锁 13 } 14 }
take()
1 public E take() throws InterruptedException { 2 final ReentrantLock lock = this.lock; 3 lock.lockInterruptibly(); // 响应中断 4 try { 5 for (;;) { 6 E first = q.peek(); // 取出队首元素 7 if (first == null) // 若为空 8 available.await(); // 说明队列为空,线程等待 9 else { 10 long delay = first.getDelay(NANOSECONDS); // 否则,获取first的delay值 11 if (delay <= 0) // 若已到期 12 return q.poll(); // 弹出此元素 13 first = null; // 线程等待时,不保持对元素的引用, 14 if (leader != null) // 领导者线程不为空,则等待 15 available.await(); 16 else { 17 Thread thisThread = Thread.currentThread(); // 否则,设置当前线程为领导者线程 18 leader = thisThread; 19 try { 20 available.awaitNanos(delay); // 等待delay时间 21 } finally { 22 if (leader == thisThread) // 等待结束后,如果自己是领导者线程,重置leader为null 23 leader = null; 24 } 25 } 26 } 27 } 28 } finally { 29 if (leader == null && q.peek() != null) // 如果自己是领导线程(上面把leader置为null了),并且有元素,则唤醒其他线程(其中一个,下一届的leader,如此循环下去) 30 available.signal(); 31 lock.unlock(); // 释放锁 32 } 33 }
leader线程,leader-follower模式,当真省去了不必要的出队入队操作(出入的是Condition的队列,出入者是唤醒又马上要等待的线程)
每一届的leader线程对应当前的队首元素,当这届leader线程拿到元素后,会空出leader位置,并唤醒其中等待时间最长的线程成为下一届的leader,如此传递下去。
行文至此结束。
尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_delayqueue.html