使用Java延時隊列DelayQueue實現訂單延時處理

DelayQueue簡單介紹

DelayQueue:一個使用優先級隊列實現的無界阻塞隊列。

支持延時獲取的元素的阻塞隊列,元素必須要實現Delayed接口。

適用場景:實現自己的緩存系統,訂單到期,限時支付等等。

具體代碼會有註釋,很好理解!

這裏我們模擬一個訂單延時處理的demo

首先我們定義一個訂單實體類

/**
 * 訂單實體類
 * @author James Lee
 *
 */
public class Order {
	// 訂單編號
	private String orderId;
	// 訂單金額
	private Double orderMoney;
	// 省略get、set等方法

}

創建存到隊列裏的元素

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
 * 存到隊列裏的元素
 * 支持延時獲取的元素的阻塞隊列,元素必須要實現Delayed接口。
 * 根據訂單有效時間作爲隊列的優先級
 * @param <T>
 */
public class ItemVo<T> implements Delayed{
	// 到期時間 單位:ms
	private long activeTime;
	// 訂單實體(使用泛型是因爲後續擴展其他業務共用此業務類)
	private T data;
	
	public ItemVo(long activeTime, T data) {
		super();
		// 將傳入的時間轉換爲超時的時刻
		this.activeTime = TimeUnit.NANOSECONDS.convert(activeTime, TimeUnit.MILLISECONDS) 
				+ System.nanoTime();
		this.data = data;
	}

	public long getActiveTime() {
		return activeTime;
	}
	public T getData() {
		return data;
	}

	// 按照剩餘時間進行排序
	@Override
	public int compareTo(Delayed o) {
		// 訂單剩餘時間-當前傳入的時間= 實際剩餘時間(單位納秒)
		long d = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
		// 根據剩餘時間判斷等於0 返回1 不等於0 
		// 有可能大於0 有可能小於0  大於0返回1  小於返回-1
		return (d == 0) ? 0 : ((d > 0) ? 1 : -1);
	}

	// 獲取剩餘時間
	@Override
	public long getDelay(TimeUnit unit) {
		// 剩餘時間= 到期時間-當前系統時間,系統一般是納秒級的,所以這裏做一次轉換
		long d = unit.convert(activeTime-System.nanoTime(), TimeUnit.NANOSECONDS);
		return d;
	}

}

創建訂單生成類

import java.util.concurrent.DelayQueue;

/**
 * 模擬訂單插入的功能
 */
public class PutOrder implements Runnable {
	
	// 使用DelayQueue:一個使用優先級隊列實現的無界阻塞隊列。
	private DelayQueue<ItemVo<Order>> queue;
	
	public PutOrder(DelayQueue<ItemVo<Order>> queue) {
		super();
		this.queue = queue;
	}

	@Override
	public void run() {
		/**
		 * 這裏模擬淘寶、京東、蘇寧的訂單,淘寶是5秒到期,京東是10秒到期,蘇寧是15秒到期
		 */
		// 淘寶訂單插入
		Order tbOrder = new Order("tb001", 9.9);
		ItemVo<Order> itemVoTb = new ItemVo<Order>(5000, tbOrder);
		queue.offer(itemVoTb);
		System.out.println("淘寶訂單5秒後過期:" + tbOrder.getOrderId());
		
		// 京東訂單插入
		Order jdOrder = new Order("jd002", 19.9);
		ItemVo<Order> itemVoJd = new ItemVo<Order>(10000, jdOrder);
		queue.offer(itemVoJd);
		System.out.println("京東訂單10秒後過期:" + jdOrder.getOrderId());
		
		// 蘇寧訂單插入
		Order snOrder = new Order("sn003", 29.9);
		ItemVo<Order> itemVoSn = new ItemVo<Order>(15000, snOrder);
		queue.offer(itemVoSn);
		System.out.println("蘇寧訂單15秒後過期:" + tbOrder.getOrderId());

	}
}

創建訂單過期取出類

import java.util.concurrent.DelayQueue;
/**
 * 取出到期的訂單的功能
 */
public class FetchOrder implements Runnable{
	
	// 使用DelayQueue:一個使用優先級隊列實現的無界阻塞隊列。
	private DelayQueue<ItemVo<Order>> queue;
	
	public FetchOrder(DelayQueue<ItemVo<Order>> queue) {
		super();
		this.queue = queue;
	}
	
	@Override
	public void run() {
		while(true) {
			try {
				// 使用DelayQueue的take方法獲取當前隊列裏的元素(take方法是阻塞方法,如果隊列裏有值則取出,否則一直阻塞)
				ItemVo<Order> itemVo = queue.take();
				// 獲取元素的實體對象,保險起見做一次強制轉型
				Order order = (Order)itemVo.getData();
				System.out.println("訂單:" + order.getOrderId()+ " 已過期!已從訂單隊列裏剔除!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}

}

測試代碼

import java.util.concurrent.DelayQueue;

/**
 * 測試
 */
public class Test {
	public static void main(String[] args) throws InterruptedException {
		DelayQueue<ItemVo<Order>> queue = new DelayQueue<ItemVo<Order>>();
		// 插入訂單
		new Thread(new PutOrder(queue)).start();
		// 取出過期訂單的線程
		new Thread(new FetchOrder(queue)).start();
		
		// 爲了看到效果,這裏沒個一秒打印一次時間,一共15秒,打印15次。
		for (int i = 1; i <= 15; i++) {
			Thread.sleep(1000);
			System.out.println("========================="+ i);
		}
	}
}

測試結果

淘寶訂單5秒後過期:tb001
京東訂單10秒後過期:jd002
蘇寧訂單15秒後過期:tb001
=========================1
=========================2
=========================3
=========================4
訂單:tb001 已過期!已從訂單隊列裏剔除!
=========================5
=========================6
=========================7
=========================8
=========================9
訂單:jd002 已過期!已從訂單隊列裏剔除!
=========================10
=========================11
=========================12
=========================13
=========================14
訂單:sn003 已過期!已從訂單隊列裏剔除!
=========================15

結果分析

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章