本文目录导读:

Java标准库本身不包含名为“DelayQueue”的类作为API,但它通过 java.util.concurrent.DelayQueue 提供了对延迟队列的原生支持。
这是一个基于优先级队列(PriorityQueue)实现的无界阻塞队列,专门用于处理需要在未来某个时间点被消费的元素。
核心API及使用方法
关键类
java.util.concurrent.Delayed:元素必须实现的接口。java.util.concurrent.DelayQueue<E extends Delayed>:延迟队列本体。java.util.concurrent.BlockingQueue:DelayQueue实现了该接口,因此具备阻塞特性。
使用步骤
第一步:实现 Delayed 接口
你的任务对象需要实现 java.util.concurrent.Delayed 接口,并定义两个方法:
getDelay(TimeUnit unit):返回当前元素剩余的有效期。compareTo(Delayed o):定义队列中元素的排序规则(最早到期的元素在队首)。
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.Date;
public class Task implements Delayed {
private final String name;
private final long startTime; // 毫秒为单位
// delayTime: 从当前时刻算起,需要延迟的秒数
public Task(String name, long delayTime) {
this.name = name;
this.startTime = System.currentTimeMillis() + delayTime;
}
// 返回剩余的延迟时间
@Override
public long getDelay(TimeUnit unit) {
long diff = startTime - System.currentTimeMillis();
return unit.convert(diff, TimeUnit.MILLISECONDS);
}
// 排序规则:剩余时间最少的排在最前面
@Override
public int compareTo(Delayed o) {
return Long.compare(this.startTime, ((Task) o).startTime);
}
@Override
public String toString() {
return "Task{" +
"name='" + name + '\'' +
", expireTime=" + new Date(startTime) +
'}';
}
}
第二步:使用 DelayQueue 进行生产和消费
import java.util.concurrent.DelayQueue;
public class DelayQueueExample {
public static void main(String[] args) throws InterruptedException {
DelayQueue<Task> delayQueue = new DelayQueue<>();
// 生产者:插入不同延迟时间的任务
System.out.println("插入任务,当前时间: " + new java.util.Date());
delayQueue.put(new Task("任务1", 2000)); // 2秒后到期
delayQueue.put(new Task("任务2", 5000)); // 5秒后到期
delayQueue.put(new Task("任务3", 1000)); // 1秒后到期
// 消费者:循环取出到期任务
while (true) {
// take() 会阻塞,直到有元素到期
Task task = delayQueue.take();
System.out.println("取出任务: " + task + " 当前时间: " + new java.util.Date());
// 3个任务都取出后退出循环(这里简单演示,取完手动退出)
if (delayQueue.isEmpty()) break;
}
}
}
输出示例:
插入任务,当前时间: Mon Jan 20 10:00:00 CST 2025
取出任务: Task{name='任务3', expireTime=Mon Jan 20 10:00:01 CST 2025} 当前时间: Mon Jan 20 10:00:01 CST 2025
取出任务: Task{name='任务1', expireTime=Mon Jan 20 10:00:02 CST 2025} 当前时间: Mon Jan 20 10:00:02 CST 2025
取出任务: Task{name='任务2', expireTime=Mon Jan 20 10:00:05 CST 2025} 当前时间: Mon Jan 20 10:00:05 CST 2025
重要方法与特点
offer(E e, long timeout, TimeUnit unit):与put类似,用于插入。take():阻塞式获取,等到第一个元素到期才返回,这是最常用的方法。poll():非阻塞式获取,如果没有到期元素,立即返回null。poll(long timeout, TimeUnit unit):带超时的阻塞式获取。peek():获取队首元素(但不移除),注意:它不会检查元素是否到期。- 无界队列:理论上可以无限添加元素,但过多元素会消耗大量内存。
实际应用场景
- 定时任务调度:按计划执行某些后台任务,如10分钟后发送通知。
- 会话超时管理:缓存用户会话,当会话过期时自动清除。
- 订单超时取消:电商中订单超过30分钟未支付,自动取消。
- 重试队列:将失败的任务放入延迟队列,5秒或10秒后重试。
注意
- 线程安全:
DelayQueue是线程安全的,可以在多线程环境中安全使用。 - 元素不可为null。
- 过期检查:
getDelay()方法返回的值必须是动态计算的(依据当前时间),因为队列内部会不断调用它来判断是否到期。 - 与
Timer/ScheduledThreadPoolExecutor的区别:DelayQueue是一个通用的数据结构,而Timer和ScheduledThreadPoolExecutor是完整的任务调度框架,前者更灵活,你可以手动控制何时取出任务;后者更常用于定时、周期性执行任务。
Java通过 java.util.concurrent.DelayQueue 提供了对延迟队列的直接、原生支持,你只需要让任务类实现 Delayed 接口并按规则编写 getDelay() 和 compareTo() 方法即可使用。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播