應(yīng)用開發(fā)過程中,我們常常需要用到延時任務(wù)的地方,
舉個栗子:
在我們提交訂單之后,15分鐘內(nèi)未支付則需要自動取消訂單,當(dāng)然,實現(xiàn)的方式有很多種,我們嘗試用延時任務(wù)方式進行。
java里自帶的延時隊列——DelayQueue即可實現(xiàn)。
什么是DelayQueue
DelayQueue——延時隊列,提供了在指定時間才能獲取隊列元素的功能。也就是說只有在隊列加入元素后指定時間間隔后才能取出元素。

DelayQueue.class
從上圖可以看出,DelayQueue是一個接口,并且繼承了Comparable,還有一個
getDelay方法。這個方法是消息是否到期(是否可以被讀取出來)判斷的依據(jù)。當(dāng)返回負數(shù),說明消息已到期,此時消息就可以被讀取出來了
所以我們需要先實現(xiàn)DelayQueue,實現(xiàn)其getDelay 和 compareTo方法(繼承了Comparable,用于延遲隊列內(nèi)部比較排序 當(dāng)前時間的延遲時間,比較對象的延遲時間)。
先上代碼:
@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) + ":任務(wù)被創(chuàng)建,任務(wù)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()) + ":任務(wù)被觸發(fā),任務(wù)id:" + delay.getTaskId());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
打印結(jié)果如下:

結(jié)果
可以看到,剛好是30秒之后才能取到隊列里的元素。