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
結果分析