意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

源码角度了解阻塞队列之DelayQueue

来源:恒创科技 编辑:恒创科技编辑部
2024-01-28 12:04:59
源码角度了解阻塞队列之DelayQueue

DelayQueue是延迟队列,在延迟到期的时候才能被获取到,按照到期时间从小到大以二叉堆的形式排列,时间最短的在堆顶的位置,它的成员遍历包括一个Condition条件,一个PriorityQueue队列,一个锁,只允许一个线程生产或消费,还有一个记录leader的线程对象。

put()方法

它的put()方法同样也是直接调用了offer()方法,我们看一下offer():

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();
        }
    }
加锁 调用PriorityQueue的offer()方法取元素 判断放入的元素如果在堆顶,leader设置为空,唤醒其他线程来消费 返回true 解锁 take()方法

take()方法的整体功能是检索并取出头部的元素,如果有需要的话等待将要到期的元素,下面我们看一下它的take()方法的源码:


源码角度了解阻塞队列之DelayQueue

public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                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
                    if (leader != null)
                        available.await();
                    else {
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            available.awaitNanos(delay);
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }
加锁 for循环,取出堆顶的元素,也就是到期时间最接近的元素 判断如果第一个元素为空,显然队列为空,就阻塞等待 否则获取第一个元素的延迟时间,如果这个元素的延迟时间小于等于0,说明已经到期,就可以从队列中取出来了,调用q.poll()进行出栈 如果延迟时间大于0,说明还没有到期,然后判断leader是否为空,如果不为空的话表示其他线程也在等待这个元素,就一直等待 如果leader为空,就把当前线程设置给leader变量,同时设置等待时间为延迟队列元素的到期时间,最后到期后如果leader等于当前线程,再设置为空 最后如果当前线程是leader并且判断还有元素,唤醒其他线程来取元素 解锁 总结

这篇文章主要介绍了DelayQueue的put()方法和take()方法,它的成员变量有PriorityQueue,放入元素和获取元素都是调用PriorityQueue实例的方法,它主要按照延迟时间来控制什么时候将元素出队

❤️ 感谢大家

如果你觉得这篇内容对你挺有有帮助的话:

欢迎关注我❤️,点赞
上一篇: coc.nvim 补全常见问题 下一篇: 手机怎么远程登录云服务器?