一、DelayQueue的概述
Java的DelayQueue 是一個阻塞隊列隊列,主要用來實現對延遲任務的調度,也就是在指定的時間之後才能夠取出任務來執行。該隊列中保存的元素都必須實現了Delayed接口。
在實際應用中,DelayQueue被廣泛地使用於緩存系統中,例如緩存的對象需要在過期時間到達後才能進行刪除。通過使用DelayQueue隊列,不必在添加緩存對象時設置過期時間,只需要在緩存對象失效後將其放入DelayQueue中,等待其到期後再執行對其的刪除操作。
二、DelayQueue的基本使用
下面是一個基本使用的例子:
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class DelayQueueExample {
static class DelayedElement implements Delayed {
private long delayTime; // 存放延遲時間
private String element; // 存放實際的任務元素
DelayedElement(long delay, String element) {
this.delayTime = System.currentTimeMillis() + delay;
this.element = element;
}
// 獲取剩餘時間
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
// 按剩餘時間進行排序
@Override
public int compareTo(Delayed o) {
return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
}
// 執行任務
public void exec() {
System.out.println("執行任務:" + element);
}
}
public static void main(String[] args) throws InterruptedException {
DelayQueue queue = new DelayQueue();
queue.add(new DelayedElement(2000, "任務1"));
queue.add(new DelayedElement(5000, "任務2"));
queue.add(new DelayedElement(3000, "任務3"));
queue.add(new DelayedElement(4000, "任務4"));
while (!queue.isEmpty()) {
DelayedElement element = queue.take();
element.exec();
}
}
}
在上述代碼中,我們創建了一個DelayQueue隊列,並向其中添加了四個基於Delayed接口的對象,設置它們的延遲時間分別為2秒、5秒、3秒和4秒。
接下來,我們使用while循環,不斷從隊列中取出任務,若隊列為空,則一直休眠直到隊列中有元素出現。當任務取出後,調用exec()方法執行任務。
三、DelayQueue的特性說明
1. 延遲任務排序
對於DelayQueue中保存的元素,隊列會按照剩餘延遲時間進行排序,以保證最先到期的任務最先被執行。當我們使用poll()、take()等方法從隊列中獲取元素時,都會取出剩餘時間最小的元素,如果延遲時間相同,則取出放入到隊列中時間最長的元素。
2. 線程安全性
DelayQueue為線程安全的隊列,可以被多個線程安全地操作。我們可以通過add()、offer()、put()、take()等方法對DelayQueue進行操作,這些方法都被設計為同步方法,具有互斥的特點。
3. DelayQueue其他方法
除了基本使用中的offer()、poll()、peek()、remove()、take()外,DelayQueue還提供了一些其他方法:
- drainTo():從隊列中取出多個元素,並將它們放入給定集合中
- drainTo():從隊列中取出所有元素,並將它們放入給定集合中
- remainingCapacity():返回隊列剩餘容量
四、DelayQueue的使用實例:訂單超時取消
一個典型的使用場景是:我們在訂單系統中需要對訂單過期時間進行檢查,到了過期時間即可取消訂單。我們可以創建如下的訂單類:
public class Order implements Delayed {
private String orderId;
private long expireTime;
public Order(String orderId, long expireTime) {
this.orderId = orderId;
this.expireTime = expireTime;
}
// 計算剩餘過期時間
@Override
public long getDelay(TimeUnit unit) {
return expireTime - System.currentTimeMillis();
}
@Override
public int compareTo(Delayed o) {
return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
}
在這個Order類中,我們需要實現Delayed接口,並覆蓋getDelay()方法,計算剩餘過期時間,以便進行排序。我們可以為它添加如下方法:
public class Order implements Delayed {
// 省略getDelay方法和compareTo方法
// 取消訂單
public void cancel() {
System.out.println("訂單[" + orderId + "]已自動取消!");
}
}
接下來我們通過如下的代碼創建DelayQueue,向其中添加訂單並檢測過期時間:
public class OrderCheckTask implements Runnable {
private DelayQueue queue;
public OrderCheckTask(DelayQueue queue) {
this.queue = queue;
}
@Override
public void run() {
try {
// 檢測訂單過期並取消過期訂單
while (true) {
Order order = queue.take();
order.cancel();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 訂單下單,加入隊列
public boolean order(Order order) {
return queue.add(order);
}
}
public class AppMain {
public static void main(String[] args) throws InterruptedException {
// 創建DelayQueue隊列
DelayQueue queue = new DelayQueue();
// 啟動訂單檢測任務
new Thread(new OrderCheckTask(queue)).start();
// 添加訂單
queue.add(new Order("A20191000", System.currentTimeMillis() + 5000));
queue.add(new Order("A20191001", System.currentTimeMillis() + 4000));
queue.add(new Order("A20191002", System.currentTimeMillis() + 6000));
queue.add(new Order("A20191003", System.currentTimeMillis() + 3000));
// 等待5秒後取消訂單
Thread.sleep(5000);
queue.add(new Order("A20191000", System.currentTimeMillis()));
// 等待15秒輸出隊列大小
Thread.sleep(15000);
System.out.println("隊列大小:" + queue.size());
}
}
在上述代碼中,我們首先創建了DelayQueue隊列和一個訂單檢測任務。在添加訂單時,我們指定延遲時間並加入DelayQueue隊列中。運行程序後,會等待5秒後,通過訂單ID刪除訂單,等待15秒後輸出DelayQueue隊列中還剩餘多少個元素。
五、DelayQueue的總結
DelayQueue主要是用來實現對延遲任務的調度,按剩餘時間排序,線程安全。我們在訂單過期檢測、緩存刪除等場景中都可以使用它。
DelayQueue的實現使用簡單,但需要我們實現Delayed接口中的getDelay()方法和compareTo()方法,並在不同的場景下調整它們的排序方式。使用好DelayQueue,將會大大提高程序處理效率。
原創文章,作者:SGDWA,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/371837.html
微信掃一掃
支付寶掃一掃