一、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-tw/n/371837.html