大家好,我是半夏之沫 😁😁 一名金融科技领域的JAVA系统研发😊😊
我希望将自己工作和学习中的经验以最朴实,最严谨的方式分享给大家,共同进步👉💓👈
👉👉👉👉👉👉👉👉💓写作不易,期待大家的关注和点赞💓👈👈👈👈👈👈👈👈
👉👉👉👉👉👉👉👉💓关注微信公众号【技术探界】 💓👈👈👈👈👈👈👈👈
前言
DelayedWorkQueue是ScheduledThreadPoolExecutor线程池使用的任务阻塞队列。DelayedWorkQueue是基于小根堆实现的延时优先级队列,队列中的元素就是ScheduledFutureTask,因此DelayedWorkQueue的队列头节点任务总是最优先被执行的任务。本篇文章将对DelayedWorkQueue的实现原理进行分析。
正文
先看一下DelayedWorkQueue的字段,如下所示。
static class DelayedWorkQueue extends AbstractQueue<Runnable>
implements BlockingQueue<Runnable> {
// 堆数组的初始大小
private static final int INITIAL_CAPACITY = 16;
// 堆数组,数组中的元素实际上是ScheduledFutureTask
private RunnableScheduledFuture<?>[] queue =
new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
private final ReentrantLock lock = new ReentrantLock();
// 延时队列元素个数
private int size = 0;
// 在延时队列头等待任务的领导线程
private Thread leader = null;
private final Condition available = lock.newCondition();
......
}
特别说明一下leader字段和available字段,首先是leader字段,表示在延时队列头等待任务的第一个线程,即如果延时队列头的任务需要被执行时,这个任务会被leader字段指向的线程获得。同时所有在延时队列头等待任务的线程,均会在available上进入等待状态,并且在延时队列头的任务需要被执行时或者延时队列头的任务被更新时唤醒所有在available上等待的线程。
已知DelayedWorkQueue是一个基于小根堆实现的延时优先级队列,那么往DelayedWorkQueue中插入和删除任务后,均需要保持堆的性质,在DelayedWorkQueue中,主要是siftUp()和siftDown()这两个方法来保持堆的性质,siftUp()是用于往DelayedWorkQueue中插入任务时来保持堆的性质,而siftDown()是用于DelayedWorkQueue弹出任务后保持堆的性质,其实现如下。
siftUp()实现如下所示。
private void siftUp(int k, RunnableScheduledFuture<?> key) {
while (k > 0) {
// 计算父节点索引
int parent = (k - 1) >>> 1;
RunnableScheduledFuture<?> e = queue[parent];
// 将插入元素与父节点元素进行比较
// 如果插入元素大于等于父节点元素,则循环结束
if (key.compareTo(e) >=

DelayedWorkQueue是ScheduledThreadPoolExecutor使用的一种基于小根堆的数据结构,用于存储ScheduledFutureTask。队列中的元素按延迟时间排序,头元素最先执行。队列的插入和删除操作通过siftUp()和siftDown()维护堆的性质。此外,文章详细介绍了添加和移除任务的逻辑,包括领导线程的概念以及take()和poll()方法的实现,这些方法考虑了任务的延迟时间和线程等待策略。
最低0.47元/天 解锁文章
611

被折叠的 条评论
为什么被折叠?



