DelayQueue延遲隊列

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

我們可以將DelayQueue運用在以下應(yīng)用場景:

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

定時任務(wù)調(diào)度:使用DelayQueue保存當(dāng)天將會執(zhí)行的任務(wù)和執(zhí)行時間,一旦從DelayQueue中獲取到任務(wù)就開始執(zhí)行,從比如TimerQueue就是使用DelayQueue實現(xiàn)的。

——以上摘自Java并發(fā)編程的藝術(shù)

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

1、用于執(zhí)行通知任務(wù)的隊列元素

packagecom.dreyer.concurrent;

importjava.util.concurrent.Delayed;

importjava.util.concurrent.TimeUnit;

/**

*@description通知延遲隊列

*@author:Dreyer

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

*/

public classNotifyTaskimplementsRunnable,Delayed {

// 通知名稱

privateStringnotifyTaskName;

// 執(zhí)行時間

private longexecuteTime;

publicNotifyTask(String notifyTaskName, longexecuteTime) {

this.notifyTaskName= notifyTaskName;

this.executeTime= executeTime;

}

/**

* 設(shè)置延遲時間

*@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("當(dāng)前時間毫秒數(shù):"+ System.currentTimeMillis() +","+this.toString() +"正在執(zhí)行...");

}

@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 {

/**

* 通知任務(wù)存放的延時隊列

*/

public staticDelayQueuetasks=newDelayQueue();

public static voidmain(String[] args) {

Random random =newRandom();

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

// 隨機產(chǎn)生一個秒數(shù)

intseconds = random.nextInt(5) +1;

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

tasks.put(notifyTask);

}

longstart = System.currentTimeMillis();

while(true) {

NotifyTask notifyTask =tasks.poll();

if(notifyTask !=null) {

notifyTask.run();

}

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

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

break;

}

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

}

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

}

}

3、執(zhí)行結(jié)果(部分)

......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

當(dāng)前時間毫秒數(shù):1461762721192,NotifyTask{notifyTaskName='任務(wù)0', executeTime=1461762721192}正在執(zhí)行...

is running......

當(dāng)前時間毫秒數(shù):1461762721192,NotifyTask{notifyTaskName='任務(wù)1', executeTime=1461762721192}正在執(zhí)行...

耗時:5ms

從結(jié)果中,我們可以看出NotifyTask的executeTime是設(shè)置在什么時候執(zhí)行,那它的執(zhí)行時間也會是那個時候

注意點:

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

關(guān)于DelayQueue在公司項目里面的應(yīng)用場景主要是:

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容