TOP 带着问题看源码
- DelayQueue 的应用场景
- DelayQueue 实现原理
1. 基本介绍
我们先来看一下它的实现类图,它实现了 Delayed、BlockingQueue 接口和 AbstractQueue 基础类,从实现的功能上看,它首先是一个阻塞队列,然后 Delayed 接口是标记给定延迟后执行的对象,结合类名也可以大致的分析出:DelayQueue 是一个 延时阻塞 队列
2. 成员变量分析
1 | // 保证线程安全的锁 |
3. 核心方法分析
3.1 入队操作
3.1.1 offer(E e)
入队逻辑很简单:
把数据加入到优先队列里
如果添加的元素是堆顶元素
2.1 leader 置空
2.2 唤醒 “可取” 条件队列的线程
1 | public boolean offer(E e) { |
3.2 出队操作
3.2.1 poll()
出队非阻塞API,核心逻辑就是:
- 检查堆顶元素,如果为空或者还没到期呢,返回 null
- 否则返回取出堆顶元素
1 | public E poll() { |
3.2.2 take()
出队阻塞API,核心逻辑就是:
- 检查堆顶元素,如果为空就等待添加元素时候被唤醒重试
- 如果不为空,并且已经过期就直接取出来,没过期并且前面没有线程等待,就等待超时时间后唤醒重试
- 每次取完都会唤醒 “可取” 条件队列的线程
1 | public E take() throws InterruptedException { |
回到问题 TOP 2 ,通过对入队列和出队列的分析,其实现原理想必已经明白,就是在队列的基础上增加了时间维度的优先级,然后通过锁和条件变量来控制取/放流程。
4. 总结
和我们开头分析的一样,DelayQueue是一个 阻塞延时且无界 的队列,它使用的是优先级队列+时间维度来实现。回到问题 TOP 1 延时队列场景主要适用于定时任务,但是对于内存中的延时队列往往不能用于重要的业务场景(毕竟还是内存队列,宕机了就没咯),所以可以应用于一些基础类库,不太重要的业务定时清理和处理等。