应用开发过程中,我们常常需要用到延时任务的地方,
举个栗子:
在我们提交订单之后,15分钟内未支付则需要自动取消订单,当然,实现的方式有很多种,我们尝试用延时任务方式进行。
java里自带的延时队列——DelayQueue即可实现。
什么是DelayQueue
DelayQueue——延时队列,提供了在指定时间才能获取队列元素的功能。也就是说只有在队列加入元素后指定时间间隔后才能取出元素。
从上图可以看出,DelayQueue是一个接口,并且继承了Comparable,还有一个
getDelay
方法。这个方法是消息是否到期(是否可以被读取出来)判断的依据。当返回负数,说明消息已到期,此时消息就可以被读取出来了
所以我们需要先实现DelayQueue,实现其getDelay
和 compareTo
方法(继承了Comparable,用于延迟队列内部比较排序 当前时间的延迟时间,比较对象的延迟时间)。
先上代码:
@Getter
@Setter
public class TestDelay implements Delayed {
private int taskId;
private Date taskTime;
// 延时30秒
private static final int EXPIRE_TIME = 30 * 1000;
@Override
public long getDelay(TimeUnit unit) {
return taskTime.getTime() + EXPIRE_TIME - System.currentTimeMillis();
}
@Override
public int compareTo(Delayed o) {
return this.taskTime.getTime() - ((TestDelay) o).taskTime.getTime() > 0 ? 1 : -1;
}
}
这里我们定义延时30秒。
然后,使用这个延时队列:
public class DelayTestApplication {
static DelayQueue<TestDelay> queue = new DelayQueue<>();
public static void main(String[] args) throws InterruptedException {
Thread createTaskThread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
e.printStackTrace();
}
createTask(i);
}
});
createTaskThread.start();
Thread checkTaskThread = new Thread(() -> {
checkTask();
});
checkTaskThread.start();
}
private static void createTask(int taskId) {
TestDelay delay = new TestDelay();
delay.setTaskId(taskId);
Date currentTime = new Date();
delay.setTaskTime(currentTime);
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(formatter.format(currentTime) + ":任务被创建,任务id:" + taskId);
queue.put(delay);
}
private static void checkTask() {
while (true) {
try {
TestDelay delay = queue.take();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(formatter.format(new Date()) + ":任务被触发,任务id:" + delay.getTaskId());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
打印结果如下:
可以看到,刚好是30秒之后才能取到队列里的元素。