DelayQueue延遲隊列

DelayQueue是一個支持延時獲取元素的無界阻塞隊列。隊列中的元素必須實現Delayed接口,在創建元素的時候可以指定多久才能從隊列中獲取當前元素,只有在延遲期滿時才能從隊列中獲取元素。

我們可以將DelayQueue運用在以下應用場景:

緩存系統的設計:可以用DelayQueue保存緩存元素的有效期,使用一個線程循環查詢DelayQueue,一旦能從DelayQueue中獲取元素時,表示緩存有效期到了。

定時任務調度:使用DelayQueue保存當天將會執行的任務和執行時間,一旦從DelayQueue中獲取到任務就開始執行,從比如TimerQueue就是使用DelayQueue實現的。

——以上摘自Java并發編程的藝術

下面是自已擼的一個小栗子

1、用于執行通知任務的隊列元素

packagecom.dreyer.concurrent;

importjava.util.concurrent.Delayed;

importjava.util.concurrent.TimeUnit;

/**

*@description通知延遲隊列

*@author:Dreyer

*@date:16/4/27 下午2:40

*/

public classNotifyTaskimplementsRunnable,Delayed {

// 通知名稱

privateStringnotifyTaskName;

// 執行時間

private longexecuteTime;

publicNotifyTask(String notifyTaskName, longexecuteTime) {

this.notifyTaskName= notifyTaskName;

this.executeTime= executeTime;

}

/**

* 設置延遲時間

*@paramunit

*@return

*/

public longgetDelay(TimeUnit unit) {

returnunit.convert(executeTime- System.currentTimeMillis(),unit.MILLISECONDS);

}

/**

* 用來指定元素的順序,讓延時時間最長的放在隊列的末尾

*@paramo

*@return

*/

public intcompareTo(Delayed o) {

NotifyTask notifyTask = (NotifyTask) o;

returnexecuteTime> notifyTask.executeTime?1: (executeTime< notifyTask.executeTime? -1:0);

}

public voidrun() {

System.out.println("當前時間毫秒數:"+ System.currentTimeMillis() +","+this.toString() +"正在執行...");

}

@Override

publicStringtoString() {

return"NotifyTask{"+

"notifyTaskName='"+notifyTaskName+'\''+

", executeTime="+executeTime+

'}';

}

}

2、測試類

packagecom.dreyer.concurrent;

importjava.util.Random;

importjava.util.concurrent.DelayQueue;

/**

*@description測試類

*@author:Dreyer

*@date:16/4/27 下午3:56

*/

public classNotifyTaskTest {

/**

* 通知任務存放的延時隊列

*/

public staticDelayQueuetasks=newDelayQueue();

public static voidmain(String[] args) {

Random random =newRandom();

for(inti =0;i <5;i++) {

// 隨機產生一個秒數

intseconds = random.nextInt(5) +1;

NotifyTask notifyTask =newNotifyTask("任務"+ i,System.currentTimeMillis() + (seconds *1000));

tasks.put(notifyTask);

}

longstart = System.currentTimeMillis();

while(true) {

NotifyTask notifyTask =tasks.poll();

if(notifyTask !=null) {

notifyTask.run();

}

// 如果隊列中的元素全部被取完,則跳出循環

if(tasks.size() ==0) {

break;

}

System.out.println("is running......");

}

System.out.println("耗時:"+ (System.currentTimeMillis() - start) /1000+"ms");

}

}

3、執行結果(部分)

......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

當前時間毫秒數:1461762721192,NotifyTask{notifyTaskName='任務0', executeTime=1461762721192}正在執行...

is running......

當前時間毫秒數:1461762721192,NotifyTask{notifyTaskName='任務1', executeTime=1461762721192}正在執行...

耗時:5ms

從結果中,我們可以看出NotifyTask的executeTime是設置在什么時候執行,那它的執行時間也會是那個時候

注意點:

栗子中的構造函數設置的延遲時間參數executeTime的單位是毫秒,getDelay()方法可以指定任意單位(栗子中指定的是毫秒),建議不要使用值過大的單位,比如秒 / 分,如果getDelay()方法返回的是一個負數,那隊列中能立即獲取到元素。

關于DelayQueue在公司項目里面的應用場景主要是:

訂單支付成功或者失敗后要給商戶發送相應的通知,針對同一條通知記錄,如果是第一次發,則需要等待的時間是0分鐘,第二次發則需要等待1分鐘,第三次發則需要等待3分鐘,即發送次數每+1,則需要等待的時長也要相應的增加,那使用DelayQueue就能很好的實現這個功能了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容