1. 程式人生 > 其它 >延時佇列 DelayQueue 的簡單使用

延時佇列 DelayQueue 的簡單使用

技術標籤:佇列java

使用場景:物聯網應用中,硬體版本升級。需要通過線上操作,對某一型別裝置,在某個時間點進行升級。

因此需要建立一個升級任務,包含了需要升級的裝置資訊,升級包,升級時間點等資訊。後臺根據升級任務,按時升級裝置。

實現方法一: 動態定時任務。

每次建立或者修改升級時間,升級時間都需要進行一次排序,已最小時間建立定時任務,並取消之前未執行的定時任務。執行完一次任務,再以下一個時間點建立定時任務。

(相對複雜,每次新增或建立都需要對升級時間進行排序,建立,取消定時任務,而且,如果更改的時間如果距離當前時間間隔短,可能會出現,建立定時任務時,任務執行的時間已經過了,導致定時任務不再執行)

方法二:

使用延時佇列 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());
		}
			
	}

}