java多线程 DelayQueue源码分析

目录

前言

成员

Leader-Follower

入队

出队

take

内存泄漏

超时poll

迭代器

总结


注意:本文转自  https://blog.csdn.net/anlian523/article/details/107801405

前言

DelayQueue是一个无界阻塞队列,它和PriorityBlockingQueue一样是一个优先队列,但区别在于队列元素只能放置Delayed对象,而且只有元素到期后才能将其出队。

内部是一个最小堆,堆顶永远是最先“到期”的那个元素。如果堆顶元素没有到期,即使线程发现队列中有元素,也不能将其出队。

DelayQueue需要依赖于元素对Delayed接口正确实现,即保证到期时间短的Delayed元素.compareTo(到期时间长的Delayed元素) < 0,这样可以让到期时间短的Delayed元素排在队列前面。

成员

//非公平的锁
private final transient ReentrantLock lock = new ReentrantLock();

//使用PriorityQueue存储元素,是个最小堆
private final PriorityQueue<E> q = new PriorityQueue<E>();

//Leader-Follower线程模式中的Leader,它总是等待获取队首
private Thread leader = null;

//不管哪种线程都将阻塞在这个条件队列上。但Follower可能是无限的阻塞
private final Condition available = lock.newCondition();

Leader-Follower

首先我们想一个问题,在队列中的处于队首的Delayed元素,由于还没到期,只能暂时等待等到它到期,这种暂时等待必然需要使用到Condition.awaitNanos。虽然第一个来的线程是可以明确知道要等队首元素多久(通过getDelay),但第二个或以后来的线程就不知道该等多久了,明显它们应该去等待排名第二或以后的元素,但奈何优先队列是个最小堆,最小堆只能时刻知道最小元素是谁。

所以,干脆让第二个或以后来的线程无限阻塞(Condition.await),但我们让第一个线程负责唤醒沉睡在条件队列上的线程。因为第一个线程总是使用Condition.awaitNanos,所以不会造成条件队列上的线程睡到天荒地老。第一个线程总是等待获得队堆顶,当它出队成功后,再唤醒后面的线程去获得新堆顶。

上面说的第一个线程其实就是Leader-Follower模式中的Leader了,它总是会以Condition.awaitNanos的方式阻塞,这保证了它不会一直沉睡。而其他线程就是所谓的Follower,当它们检测到Leader的存在时,则可以放心使用Condition.await,就好像调好了闹钟所以可以放心大胆睡觉一样。

入队

    public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.offer(e);
            if (q.peek() == e) {
                leader = null;
                available.signal();
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

lock.lock()入队不响应中断,也没有必要响应

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值