DelayQueue 源码分析 - 特点与新增
前言
DelayQueue 通常被称为延迟队列,在实际使用中,可以设置延迟多长时间执行,在一些延迟执行的场景中比较适合,比如说延迟转账等。
DelayQueue 底层的大致实现思路是使用锁的能力,比如延迟 5s,则当前线程就会睡眠 5s,当睡眠结束被唤醒后,会尝试获取资源,能获取到则会马上执行,这只是简述,当然内部实现是比较复杂的。
特点
队列中元素将在过期时被执行,越靠近队头,越早过期
未过期的元素不能够被 take
不允许存在空元素
DelayQueue 的类定义:
泛型约定了,DelayQueue 中的元素必须是 Delayed 的子类,Delayed 是定义延迟能力的关键接口,并且继承了 Comparable 接口,定义了还剩多久过期的方法:
所以 DelayQueue 队列中的元素必须是实现 Delayed 接口的,并需要覆写 getDelay 方法和 compareTo 的方法。
put()
put 方法主要是用于往 DelayQueue 中放入数据,源码:
put 内部主要调用的是 offer 方法,offer 方法中:lock.lock();
上锁
q.offer(e);
调用 PriorityQueue 的扩容、排序等方法
if (q.peek() == e) { leader = null; available.signal(); }
如果恰好刚放进去的元素正好在队列头,立马唤醒 take 的阻塞线程,执行 take 操作,如果元素需要延迟执行的话,可以使其更快的沉睡计时
lock.unlock();
释放锁
PriorityQueue 的 offer 方法源码:
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 比队列中元素大的位置
版权声明: 本文为 InfoQ 作者【zarmnosaj】的原创文章。
原文链接:【http://xie.infoq.cn/article/e54a08687cfe0a35bc6879775】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论