Java 中的 DelayQueue 和 ScheduledThreadPool 有什么区别?
Java 中的 DelayQueue 和 ScheduledThreadPool 有什么区别?
回答重点
DelayQueue 是一个阻塞队列,而 ScheduledThreadPool 是线程池,不过内部核心原理都是差不多的。
DelayQueue 是利用优先队列存储元素,当从队列中获取任务的时候,如果最老的任务已经到了执行时间,可以从队列中出队一个任务,反之可以获得 null 或者阻塞等待任务到时。
ScheduledThreadPool 内部也使用的一个优先队列 DelayedWorkQueue 且可以内部多线程执行任务,支持定时执行的任务,即每隔一段时间执行一次的任务。
扩展
DelayQueue 源码分析
首先,DelayQueue 中存储的所有元素必须实现 Delayed 接口,内部使用了优先级队列来存储元素,PriorityQueue 能保证优先级最高的元素优先出队。

添加元素
在添加元素的时候,会利用 ReentrantLock 上锁,实现添加元素的并发安全:

q.peek() 会返回优先级队列中最小的元素,这里的最小指的是延迟时间最短,最快需要执行的元素。
如果这个元素就是刚插入的元素,说明这个元素可能需要马上执行,因此立马通过 condition 的 signal 唤醒等待拿元素的线程。这个动作是为了确保队列的头部元素总是能够及时被处理。
阻塞获取元素
take 方法的逻辑其实很简单,看下面的源码注解应该就很清晰了:

所以 DelayQueue 的本质就是使用了 PriorityQueue+lock+condition 来实现的。
DelayedWorkQueue 源码分析
实际上 DelayedWorkQueue 和 DelayQueue 几乎一模一样,差别就是 DelayedWorkQueue 没有使用 PriorityQueue 而是用 RunnableScheduledFuture 数组来实现了优先级队列,不过底层原理都是一样的。
我们来看下 take 方法,就能知道它们的实现没什么差别了:

所以 DelayedWorkQueue 的本质就是使用了 RunnableScheduledFuture+lock+condition 来实现的。