目录
DelayQueue简介
DelayQueue
是 Java 中一个实现延时任务的无界阻塞队列。它是 Java 并发包(java.util.concurrent
)的一部分,专门用于在延迟一定时间后才能提取元素的场景。
DelayQueue继承体系
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E>
可以看到DelayQueue实现了BlockingQueue接口和Delayed接口。 实现BlockingQueue接口说明支持阻塞和线程安全。
DelayQueue<E extends Delayed> 泛型,表明DelayQueue存储的元素必须继承或者实现Delayed接口。
Delayed接口
package java.util.concurrent;
public interface Delayed extends Comparable<Delayed> {
/**
* Returns the remaining delay associated with this object, in the
* given time unit.
*
* @param unit the time unit
* @return the remaining delay; zero or negative values indicate
* that the delay has already elapsed
*/
long getDelay(TimeUnit unit);
}
Delayed
是一个标记接口,要求实现以下方法:
getDelay(TimeUnit unit)
:返回元素还需等待的时间,时间单位由参数unit
指定。compareTo(Delayed other)
:Delayed 接口继承了 Comparable 接口,因此实现了该接口的对象可以根据其延迟时间进行比较和排序。这使得 DelayQueue 能够始终将延迟时间最短(即最早到期)的元素放在队列头部
DelayQueue的基本原理
//锁,保证多并发情况下线程安全
private final transient ReentrantLock lock = new ReentrantLock();
//队列
private final PriorityQueue<E> q = new PriorityQueue<E>();
DelayQueue
内部维护了一个基于时间排序的优先队列(PriorityQueue
)。每个插入队列的元素都必须实现 Delayed
接口,该接口要求实现 getDelay(TimeUnit unit)
方法,用来指定元素在队列中剩余的延迟时间。当队列的头元素(即优先级最高的元素)延迟时间为零或负数时,才允许被提取。
DelayQueue应用场景
任务调度:
- 在规定时间后执行某些任务,如定时发送消息、定时执行批处理任务。
缓存过期管理:
- 将缓存数据放入
DelayQueue
,设置缓存的过期时间,当时间到期后自动删除或处理这些缓存。限速器:
- 用于限制某些操作的执行频率,例如 API 调用频率控制。
DelayQueue简单示例
场景描述
假设有一个在线购物系统,当用户下单后,如果在30分钟内没有付款,则自动取消订单。为了实现这一功能,可以使用
DelayQueue
结合线程池异步处理,实现延时任务触发。
设计思路
- 任务:表示订单的延时取消操作
- 线程池:利用异步执行操作,确保系统可以处理高并发的延时任务
- DelayQueue:用于管理延时任务,根据任务的延时时间自动触发
代码实现
import java.util.concurrent.*;
// 定义订单类,实现Delayed接口
class Order implements Delayed {
private String orderId;
private long startTime; // 延时时间
public Order(String orderId, long delayTime) {
this.orderId = orderId;
this.startTime = System.currentTimeMillis() + delayTime;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(startTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
}
public String getOrderId() {
return orderId;
}
public void cancel() {
System.out.println("Order " + orderId + " is cancelled.");
}
}
public class DelayedOrderCancellation {
// 创建线程池和DelayQueue
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
private static final DelayQueue<Order> delayQueue = new DelayQueue<>();
public static void main(String[] args) {
// 模拟创建订单并添加到DelayQueue中,延时30分钟(30 * 60 * 1000 毫秒)
Order order1 = new Order("1001", 30 * 60 * 1000);
delayQueue.put(order1);
// 启动异步任务处理线程
executor.execute(() -> {
while (true) {
try {
// 从DelayQueue中取出已到期的任务
Order order = delayQueue.take();
order.cancel(); // 取消订单
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
// 模拟系统其他业务逻辑...
}
}
代码说明
- Order类:实现
Delayed
接口,包含订单ID和延时时间。在getDelay
方法中计算剩余的延时时间,在compareTo
方法中进行比较。- DelayQueue:
DelayQueue
是一个无界阻塞队列,用于管理Delayed
元素。只有到期的元素才能被取出。- 线程池:使用
ExecutorService
来异步处理订单的取消任务,防止主线程阻塞。- 延时任务处理:在
executor
中运行的线程不断从DelayQueue
中获取到期的订单并执行取消操作。
DelayQueue
为 Java 并发编程提供了强大的延时任务支持,适用于需要时间控制的任务调度场景。