自己实现一个有界延时阻塞队列DelayQueue

自己实现一个有界延时阻塞队列DelayQueue

前言

最近闲来无事,看了下J.U.C并发包中的队列,看到了DelayQueue和DelayedWorkQueue无界延时阻塞队列,底层数据结构都是数组实现的优先级队列,lock实现并发和阻塞,因为是无界的所以入队不需要阻塞,而出队时根据情况进行阻塞,所以想着来自己实现一个有界的延时阻塞队列.

1.准备工作

首先新建接口SiftDelayRunnableInterface作为队列元素顶层接口继承Comparable和Runnable因为是优先级队列,所以要继承Comparable接口在元素入队时需要根据延时时间进行比较,始终将延时时间最少的放在队首,
这里getDelay是获取元素的延时时间1

2.队列的核心参数

在这里插入图片描述
(1). 既然是阻塞队列必须得继承BlockingQueue泛型是Runnable,这也是刚才的接口必须继承Runnale的原因
(2). 队列的泛型必须继承刚才的接口,也就是队列中的元素是SiftDelayRunnableInterface接口的实现类
(3). count:队列大小
(4). item:存放队列元素,用数组实现
(5). lock同步锁 full:数组长度等于队列长度时的阻塞条件 empty:队列中没有元素时的阻塞条件
(6). leader占位线程,在元素出队时用到

3.核心方法offer(入队)

在这里插入图片描述
(1).元素入队时,若队列长度等于数组长度时,通过lock阻塞当前线程.
(2).若当前是第一个元素,添加到队首,并且lock唤醒消费线程(消费线程可能阻塞)
(3).如不是,用siftUp方法,将元素添加到队列中.
siftUp方法:
在这里插入图片描述
(1).因为是优先级队列,所以需要通过排序将时间最小的放在队首(这里是使用的堆排序,类似二叉树结构)

4.核心方法take(元素出队)

在这里插入图片描述
(1).自旋得到队首的元素,若队首元素为null,则lock等待直到被唤醒,
(2).若不为null,首先判断元素延时时间是否过期,过期直接用firstPoll方法返回首节点元素,并删除首节点元素.
(3).延时时间没有过期,判断leader是否为null.不为null,说明在当前线程之前没有其他线程过来取元素,直接将leader设置成当先元素,并过期延时等待,等待时间到自动唤醒置空leader,循环返回队首元素
(4).finally最后判断leader和判断队首元素满足条件唤醒下一个等待获取队首元素的线程,下一个线程循环重新获取队首元素在进行一样的判断.

firstPoll和siftSown方法:
在这里插入图片描述
(1).取出队首元素并删除,首先获取队尾元素,将队尾元素置null,
(2).从队首开始比较左右子节点大小,找到子节点最小的与队尾最后元素比较,子节点比队尾元素小交换位置,在比较子节点的左右节点大小,以此类对.

5.队列中自己维护一个SiftDelay类

在这里插入图片描述
(1).也可以自定义实现类,继承SiftDelayRunnableInterface接口,看注释

6.自定义两个入队方法

在这里插入图片描述

7.测试

在这里插入图片描述
在这里插入图片描述
(1).添加一个周期三秒的任务

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的DelayQueue一个特殊的队列,它只允许在指定的延迟时间之后才能从队列中取出元素。可以使用DelayQueue实现一些延迟任务的功能,例如任务调度、缓存过期等。 DelayQueue基于PriorityQueue实现,但是它的元素必须实现Delayed接口,Delayed接口中定义了一个getDelay()方法,返回元素的延迟时间。 当从DelayQueue中取出元素时,如果该元素的延迟时间还没有到达,则该元素会被重新加入队列中,直到延迟时间到达。 以下是一个简单的使用DelayQueue的例子: ```java import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class DelayQueueExample { public static void main(String[] args) throws InterruptedException { DelayQueue<DelayedElement> delayQueue = new DelayQueue<DelayedElement>(); delayQueue.add(new DelayedElement("element1", 2000)); delayQueue.add(new DelayedElement("element2", 5000)); delayQueue.add(new DelayedElement("element3", 1000)); while (!delayQueue.isEmpty()) { DelayedElement element = delayQueue.take(); System.out.println("Taking element: " + element); } } static class DelayedElement implements Delayed { private String name; private long delayTime; public DelayedElement(String name, long delayTime) { this.name = name; this.delayTime = System.currentTimeMillis() + delayTime; } @Override public long getDelay(TimeUnit unit) { long diff = delayTime - System.currentTimeMillis(); return unit.convert(diff, TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed o) { if (this.delayTime < ((DelayedElement) o).delayTime) { return -1; } if (this.delayTime > ((DelayedElement) o).delayTime) { return 1; } return 0; } @Override public String toString() { return "DelayedElement{" + "name='" + name + '\'' + ", delayTime=" + delayTime + '}'; } } } ``` 在上面的例子中,我们创建了一个DelayQueue,并向其中添加了三个DelayedElement元素。每个元素都有一个延迟时间,分别为2秒、5秒和1秒。 在主线程中,我们不断地从DelayQueue中取出元素,直到队列为空。当元素的延迟时间还没有到达时,它会被重新加入队列中,直到延迟时间到达。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值