延時佇列 DelayQueue 的簡單使用
阿新 • • 發佈:2021-01-12
使用場景:物聯網應用中,硬體版本升級。需要通過線上操作,對某一型別裝置,在某個時間點進行升級。
因此需要建立一個升級任務,包含了需要升級的裝置資訊,升級包,升級時間點等資訊。後臺根據升級任務,按時升級裝置。
實現方法一: 動態定時任務。
每次建立或者修改升級時間,升級時間都需要進行一次排序,已最小時間建立定時任務,並取消之前未執行的定時任務。執行完一次任務,再以下一個時間點建立定時任務。
(相對複雜,每次新增或建立都需要對升級時間進行排序,建立,取消定時任務,而且,如果更改的時間如果距離當前時間間隔短,可能會出現,建立定時任務時,任務執行的時間已經過了,導致定時任務不再執行)
方法二:
使用延時佇列 DelayQueue實現。每次建立或修改升級時間,都往佇列中新增一個元素,延時時間(通過升級時間點計算)。元素中,需包含任務id,和版本(識別任務時間是否更改過,確保裝置升級時間點準確)。
(無須自己排序,只要計算好延時時長即可)
考慮情況: 叢集部署(用分散式鎖,可以使用redis實現),服務掛了(專案重新啟動,需要對未執行的任務重新放進佇列),任務執行中斷(部分裝置未進行升級,如何處理)等等。。。
package com.rsh.demo.delayq; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class MyDelay implements Delayed { // 延時時長,單位自定義 private long delayTime; private String name; public MyDelay(long delayTime, String name) { this.name = name; // 比如使用s this.delayTime = delayTime * 1000 + System.currentTimeMillis(); } public MyDelay() {} public long getDelayTime() { return this.delayTime; } public String getName() { return this.name; } @Override public int compareTo(Delayed o) { return (int) (this.delayTime - ((MyDelay) o).getDelayTime()); } // unit.convert 根據自己需要更改 @Override public long getDelay(TimeUnit unit) { return unit.convert((this.delayTime-System.currentTimeMillis()), TimeUnit.MILLISECONDS); } public static void main(String[] args) throws InterruptedException { DelayQueue<MyDelay> delayQueue = new DelayQueue<>(); MyDelay delay; long delayTime; for(int i= 0; i < 10; i++) { delayTime = (long) (Math.random() * 100L); System.out.println(delayTime); delay = new MyDelay(delayTime, delayTime+""); delayQueue.put(delay); } for(int i=0; i< 10; i++) { delay = delayQueue.take(); System.err.println("name= "+delay.getName()); } } }