一、延时队列介绍
延时队列是一种基于优先级队列 PriorityQueue
和 Delay
接口实现的队列。该队列中的元素必须实现 Delay
接口,表明当前元素需要在指定时间之后才能被处理。队列按照 Delay
时间进行排序,越早需要处理的元素越排在前面。
二、Delay接口与元素实现
Delay
接口中定义了 getDelay(TimeUnit unit)
方法,该方法返回当前元素距离激活时间还有多少时间。元素实现 Delay
接口时需要实现该方法。
public interface Delayed extends Comparable<Delayed> {
long getDelay(TimeUnit unit);
}
元素需要实现该接口,并实现 getDelay(TimeUnit unit)
方法。一般来说,需要获取当前任务的激活时间与现在时间的差值(单位可以是毫秒、秒等),然后调用 convert()
方法转换为指定的 TimeUnit
时间单位。
public class Message implements Delayed {
private int id;
private String content;
private long activeTime;
public Message(int id, String content, long delayTime) {
this.id = id;
this.content = content;
this.activeTime = System.currentTimeMillis() + delayTime;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(activeTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
Message other = (Message) o;
return Long.compare(activeTime, other.activeTime);
}
// getter and setter methods
}
三、延时队列的实现与使用
Java 中提供了 DelayQueue
类实现延时队列。DelayQueue
是线程安全的队列,它实现了 BlockingQueue
接口,提供了以下方法:
add(E e)
:将元素添加到队列中,并处于激活状态。offer(E e, long timeout, TimeUnit unit)
:添加一个元素,并阻塞指定的时间等待队列空间。take()
:移除并返回队列头部的元素,若队列为空则阻塞等待。poll(long timeout, TimeUnit unit)
:移除并返回队列头部的元素,若队列为空则阻塞等待指定时间后返回 null。isEmpty()
:判断队列是否为空。size()
:返回队列中的元素个数。
public class DelayQueueDemo {
public static void main(String[] args) throws InterruptedException {
DelayQueue<Message> queue = new DelayQueue<>();
// add messages to the queue
queue.add(new Message(1, "Hello World!", 5_000)); // delay 5s
queue.add(new Message(2, "Hi World!", 3_000)); // delay 3s
queue.add(new Message(3, "Goodbye World!", 7_000)); // delay 7s
// take and print messages from the queue
while(!queue.isEmpty()) {
Message message = queue.take();
System.out.println(message.getContent());
}
}
}
四、延时队列的应用场景
延时队列常用于定时任务、定时器等需要在指定时间后进行操作的场景。例如:
- 短信/邮件的发送定时处理
- 缓存失效的自动清除
- 高并发下的请求限流与熔断
- 定时扫描并处理过期的数据
五、总结
Java 延时队列是一种基于优先级队列 PriorityQueue
和 Delay
接口实现的队列。其常用于定时任务、定时器等需要在指定时间后进行操作的场景。可以通过实现 Delay
接口和 Comparator
接口来自定义元素,放入 DelayQueue
中实现自己的业务逻辑。