DelayedQueue队列

本文深入探讨了Java并发包中的DelayQueue,一种特殊的无界阻塞队列。通过具体实例介绍了其工作原理,包括如何存储实现了Delayed接口的对象及这些对象的排序方式。文章还详细解释了PriorityQueue在DelayQueue中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DelayQueue是一个无界的BlockingQueue,用于存储实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。注意:不能将null元素放置到这种队列中。
下面先看一个例子:
/**
 * DelayQueue需要存储的对象的类,实现Delayed接口,重写compareTo和getDelay方法
 */
class DelayedQueueEvent implements Delayed {
     private Long startDate;
     
     private String name;
     public DelayedQueueEvent(Long startDate, String name) {
           this.startDate = startDate;
           this.name = name;
     }
     public String getName() {
           return this.name;
     }

     @Override
     public int compareTo(Delayed o) {
           long result = this.getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
           if (result < 0) {
                return -1;
           } else if (result > 0) {
                return 1;
           }
           return 0;
     }

     @Override
     public long getDelay(TimeUnit unit) {
           long diff = startDate - System.currentTimeMillis();
           return unit.convert(diff, TimeUnit.MILLISECONDS);
     }
}

public class DelayedQueueDemo {
     public static void main(String[] args) throws Exception {
           DelayQueue<DelayedQueueEvent> queue = new DelayQueue<>();
           for (int i = 0; i < 10; i++) {
                //startDate启动时间为当前时间延后5秒的整数倍
                DelayedQueueEvent event = new DelayedQueueEvent(System.currentTimeMillis() + (i+1) * 5000, String.valueOf(i));
                queue.add(event);
           }
           System.out.println("当前时间:"+ new Date());
           
           DelayedQueueEvent event;
           while (queue.size() != 0) {
                event = queue.poll();
                if (event != null) {
                     System.out.println("取出" + event.getName() + ":" + new Date());
                }
           }
           
     }
}

运行结果如下:


由结果可知每5秒从DelayQueue中取出一个元素。
例子很简单,那么有两个问题:
1.添加的元素为什么需要排序呢?
查看源码可知:

private final PriorityQueue<E> q = new PriorityQueue<E>();

public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E first = q.peek();
            if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
                return null;
            else
                return q.poll();
        } finally {
            lock.unlock();
        }
    }
原因是DelayQueue采用了PriorityQueue来存储数据,而PriorityQueue所存储的元素是有序的。
2.compareTo方法应该返回什么样的排序?
此接口的实现必须定义一个compareTo方法,该方法提供与此接口的 getDelay方法一致的排序
从以上的源码也可以看出,从DelayQueue获取元素时候,是获取PriorityQueue的头元素,并判断是否到达执行的时间,如果没到执行时间,返回null。如果 compareTo提供的排序和getDelay不一致,那么该处就会有问题,就会出现到达执行时间的元素没有被取出。

注意:
getDelay方法返回与此对象相关的剩余延迟时间,以给定的时间单位表示, 查看源码可知DelayQueue给的单位是纳秒.

### Java队列的实现与用法 #### 1. 基本概念 队列是一种遵循先进先出(FIFO, First In First Out)原则的数据结构。这意味着最早进入队列的元素会最先被移除。可以使用数组或者链表来实现这种数据结构[^4]。 #### 2. 使用标准库中的队列接口和类 Java 提供了 `Queue` 接口以及多个实现了该接口的具体类,比如 `LinkedList`, `ArrayDeque` 和 `PriorityQueue`. 这些集合框架内的组件简化了开发者创建不同类型的队列的工作: - **`LinkedList<E>`**: 双向链接列表既可作为列表也可当作堆栈或队列使用; - **`ArrayDeque<E>`**: 数组支持的双端队列,适合作为高效的非阻塞 FIFO 队列; - **`PriorityQueue<E>`**: 支持优先级排序的无界队列[^2]. ```java // 创建并初始化一个基于双向链表的队列 Queue<String> queue = new LinkedList<>(); queue.offer("First Item"); queue.offer("Second Item"); System.out.println(queue.poll()); // 输出:"First Item" System.out.println(queue.peek()); // 输出:"Second Item", 不改变队列状态 ``` #### 3. 自定义顺序队列 对于特定需求的应用场景下,可能需要自定义队列的行为逻辑。下面展示了一个简单的固定大小循环缓冲区形式的顺序队列例子[^3]: ```java public class CircularQueue { private final int[] data; private int head = 0; private int tail = 0; public CircularQueue(int capacity) { this.data = new int[capacity]; } public boolean enqueue(int value) { if ((tail + 1) % data.length == head) return false; // full check data[tail] = value; tail = (tail + 1) % data.length; return true; } public Integer dequeue() { if (head == tail) return null; // empty check var result = data[head]; head = (head + 1) % data.length; return result; } } ``` #### 4. 特殊用途的延时队列 除了常规操作外,在某些情况下还需要处理带有时间延迟特性的消息传递机制。为此有两种常见做法:一是利用 Java 内置工具如 `ScheduledExecutorService`;二是借助第三方库例如 Redisson 来构建分布式环境下的解决方案[^1]. ```java import org.redisson.api.RDelayedQueue; import org.redisson.api.RedissonClient; // 初始化Redisson客户端实例... RDelyedQueue<Object> delayedQueue = redisson.getDelayedQueue("myQueueName"); delayedQueue.add(new MyTask(), Duration.ofSeconds(5)); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值