zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    WCF 连接数
    职责链(Chain of Responsibility)模式
    軟件需求分析說明書模板
    C++指針淺析(1)
    ORACLE NOCOPY的用法
    解释器模式(Interpreter Pattern)
    不用嵌套SQL,排序後取第一行值
    Java SE/EE剖析工具JProfiler 7发布了:探针、线程和堆检查
    三款Json查看小工具
    用Data Factory准备性能测试数据
  • 原文地址:https://www.cnblogs.com/aniao/p/aniao_delayqueue.html
Copyright © 2011-2022 走看看