写点什么

DelayQueue 源码分析 - 特点与新增

作者:zarmnosaj
  • 2022 年 7 月 08 日
  • 本文字数:1421 字

    阅读完需:约 5 分钟

前言

DelayQueue 通常被称为延迟队列,在实际使用中,可以设置延迟多长时间执行,在一些延迟执行的场景中比较适合,比如说延迟转账等。


DelayQueue 底层的大致实现思路是使用锁的能力,比如延迟 5s,则当前线程就会睡眠 5s,当睡眠结束被唤醒后,会尝试获取资源,能获取到则会马上执行,这只是简述,当然内部实现是比较复杂的。

特点

  1. 队列中元素将在过期时被执行,越靠近队头,越早过期

  2. 未过期的元素不能够被 take

  3. 不允许存在空元素


DelayQueue 的类定义:


public class DelayQueue<E extends Delayed> extends AbstractQueue<E>    implements BlockingQueue<E> {    ..    }
复制代码


泛型约定了,DelayQueue 中的元素必须是 Delayed 的子类,Delayed 是定义延迟能力的关键接口,并且继承了 Comparable 接口,定义了还剩多久过期的方法:


public interface Delayed extends Comparable<Delayed> {    long getDelay(TimeUnit unit);}
复制代码


所以 DelayQueue 队列中的元素必须是实现 Delayed 接口的,并需要覆写 getDelay 方法和 compareTo 的方法。

put()

put 方法主要是用于往 DelayQueue 中放入数据,源码:


    public void put(E e) {        offer(e);    }        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();    }}
复制代码


put 内部主要调用的是 offer 方法,offer 方法中:lock.lock(); 上锁


q.offer(e); 调用 PriorityQueue 的扩容、排序等方法


if (q.peek() == e) { leader = null; available.signal(); } 如果恰好刚放进去的元素正好在队列头,立马唤醒 take 的阻塞线程,执行 take 操作,如果元素需要延迟执行的话,可以使其更快的沉睡计时


lock.unlock(); 释放锁


PriorityQueue 的 offer 方法源码:


public boolean offer(E e) {    if (e == null)        throw new NullPointerException();    modCount++;    int i = size;    if (i >= queue.length)        grow(i + 1);    size = i + 1;    if (i == 0)        queue[0] = e;    else        siftUp(i, e);    return true;}
private void siftUpComparable(int k, E x) { Comparable<? super E> key = (Comparable<? super E>) x; while (k > 0) { int parent = (k - 1) >>> 1; Object e = queue[parent]; if (key.compareTo((E) e) >= 0) break; queue[k] = e; k = parent; } queue[k] = key; }
复制代码


if (e == null) throw new NullPointerException(); 判断是否是空元素,是则抛异常


if (i >= queue.length) grow(i + 1);队列实际大小大于容量时,进行扩容(策略:如果老容量小于 64,2 倍扩容,如果大于 64,50 % 扩容)


if (i == 0) queue[0] = e;如果队列为空,当前元素正好处于队头


else { siftUp(i, e); } 如果队列不为空,需要根据优先级进行排序


siftUpComparable 方法(从小到大排序)中:while (k > 0) { } 判断 k 是否在当前队列实际大小的位置


int parent = (k - 1) >>> 1; 对 k 进行减倍


if (key.compareTo((E) e) >= 0) break;如果 x 比 e 大,退出,把 x 放在 k 位置上,x 比 e 小,继续循环,直到找到 x 比队列中元素大的位置

发布于: 刚刚阅读数: 4
用户头像

zarmnosaj

关注

靡不有初,鲜克有终 2020.02.06 加入

成都后端混子

评论

发布
暂无评论
DelayQueue源码分析-特点与新增_7月月更_zarmnosaj_InfoQ写作社区