DelayQueue源码

DelayQueue源码

DelayQueue是一个支持延时获取元素的无界阻塞队列。队列使用PriorityQueue来实现。队 列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。 只有在延迟期满时才能从队列中提取元素

public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E> {

    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();

}

DelayQueue内部使用PriorityQueue作为阻塞队列,使用ReentrantLock实现线程同步,并且使用了leader-fellower设计模式,如果要加入到DelayQueue,必须实现Delayed接口

offer插入队列
public boolean offer(E e) {
   final ReentrantLock lock = this.lock;
   //获取独占锁
   lock.lock();
   try {
       //插入队列
       q.offer(e);
       //如果插入的e是队头元素,并且e即将过期,则通知其他线程进行take()操作
       if (q.peek() == e) {
           leader = null;
           available.signal();
       }
       return true;
   } finally {
       lock.unlock();
   }
}
take队列取数据

等待过期的数据,移除并删除

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    //获取独占锁,允许被中断
    lock.lockInterruptibly();
    try {
        for (;;) {
            //取出但不删除队列中数据e
            E first = q.peek();
            //如果没有即将过期的数据,则等待,让出独占锁
            if (first == null)
                available.await();
            //处理即将过期的元素
            else {
                //计算元素还有多少时间过期
                long delay = first.getDelay(NANOSECONDS);
                //如果已经到期,则出队列,并从队列中删除该元素
                if (delay <= 0)
                    return q.poll();
                first = null; // don't retain ref while waiting
                //时间未到,并且leader不等于null,则等待。主要是采用了leader-fellower pattern有关
                if (leader != null)  
                    available.await();
                else {
                    Thread thisThread = Thread.currentThread();
                    //时间未到,leader为空时,将leader设置成当前线程
                    leader = thisThread;
                    try {
                        //leader线程等待delay时间内挂起等待,等待之后让出leader,即leader=null
                        available.awaitNanos(delay);
                    } finally {
                        if (leader == thisThread)
                            leader = null;
                    }
                }
            }
        }
    } finally {
        //队列中有数据,且leader为空,则需要唤醒一下condition available等待队列上的线程,重新竞争锁,然后从挂起处继续执行
        if (leader == null && q.peek() != null)
            available.signal();
        lock.unlock();
    }
}
了解Leader-fellower pattern

所有线程会有三种身份中的一种:leader和follower,以及一个干活中的状态:proccesser。它的基本原则就是,永远最多只有一个leader。而所有follower都在等待成为leader。线程池启动时会自动产生一个Leader负责等待网络IO事件,当有一个事件产生时,Leader线程首先通知一个Follower线程将其提拔为新的Leader,然后自己就去干活了,去处理这个网络事件,处理完毕后加入Follower线程等待队列,等待下次成为Leader。这种方法可以增强CPU高速缓存相似性,及消除动态内存分配和线程间的数据交换

一个比较好的比喻 https://stackoverflow.com/questions/3058272/explain-leader-follower-pattern

DelayQueueLeader-fellower模式

  • 有多个线程操作take时,只有leader线程会生效
  • leader!=null,其它的take线程均为follower,主要体现在available.await()
  • 如果leader == null,就将当前线程设置成leader
  • 如果线程中队列元素到期,并且leader等于null,则唤醒其他操作take的线程,从中选出作为五个leader
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值