應(yīng)用開發(fā)過程中,我們常常需要用到延時(shí)任務(wù)的地方英染,
舉個(gè)栗子:
在我們提交訂單之后揽惹,15分鐘內(nèi)未支付則需要自動取消訂單被饿,當(dāng)然,實(shí)現(xiàn)的方式有很多種搪搏,我們嘗試用延時(shí)任務(wù)方式進(jìn)行狭握。
java里自帶的延時(shí)隊(duì)列——DelayQueue即可實(shí)現(xiàn)。
什么是DelayQueue
DelayQueue——延時(shí)隊(duì)列疯溺,提供了在指定時(shí)間才能獲取隊(duì)列元素的功能哥牍。也就是說只有在隊(duì)列加入元素后指定時(shí)間間隔后才能取出元素。
從上圖可以看出喝检,DelayQueue是一個(gè)接口嗅辣,并且繼承了Comparable,還有一個(gè)
getDelay
方法挠说。這個(gè)方法是消息是否到期(是否可以被讀取出來)判斷的依據(jù)澡谭。當(dāng)返回負(fù)數(shù),說明消息已到期损俭,此時(shí)消息就可以被讀取出來了
所以我們需要先實(shí)現(xiàn)DelayQueue蛙奖,實(shí)現(xiàn)其getDelay
和 compareTo
方法(繼承了Comparable,用于延遲隊(duì)列內(nèi)部比較排序 當(dāng)前時(shí)間的延遲時(shí)間杆兵,比較對象的延遲時(shí)間)雁仲。
先上代碼:
@Getter
@Setter
public class TestDelay implements Delayed {
private int taskId;
private Date taskTime;
// 延時(shí)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;
}
}
這里我們定義延時(shí)30秒。
然后琐脏,使用這個(gè)延時(shí)隊(duì)列:
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é)果如下:
可以看到攒砖,剛好是30秒之后才能取到隊(duì)列里的元素。