這篇文章我們來講講BlockingQueue阻塞隊列的另一個實現DelayQueue,先前我們的文章中有介紹LinkedBlockingQueue,而DelayQueue與之不同的是,DelayQueue裏面哪怕有元素也無法取出,除非元素已經到期,而LinkedBlockingQueue只要裏面有元素就可以取出!
所以,你可以往DelayQueue中存放一個元素,且聲明在半小時後才失效。那麼往此隊列中取元素的線程將會阻塞半小時,直到半小時後才能拿到元素進行下一步動作,這樣的話,你就可以變相實現定時執行任務了;當然,我們是不會這樣來用的,定時任務有更完美的解決方案,這個我們後面再介紹;
class DelayTask implements Delayed,Runnable{
long trigger = 0;//觸發時間,也就是隊列中的元素失效時間
int id = 0;
long delayMilliSecound = 0;//等待時間
public DelayTask( long delayMilliSecound,int id) {
this.delayMilliSecound = delayMilliSecound;
this.trigger = System.currentTimeMillis()+delayMilliSecound;
this.id = id;
}
@Override
public int compareTo(Delayed arg) {
DelayTask delay = (DelayTask) arg;
if(this.trigger==delay.trigger){
return 0;
}
//必須要越晚到期的元素越排後,因爲隊列是先進先出的,最先彈出的元素是隊頭,所以隊頭必須是最先到期的
//當然,如果不這樣做也不會有任何報錯,只是,本來等待3秒某個任務必須要執行了
//但由於隊頭要等待10秒,在隊頭沒有被彈出之前,該任務是無法彈出的;
return this.trigger > delay.trigger?1:-1;
}
//返回與此對象相關的剩餘延遲時間,以給定的時間單位表示。
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(trigger-System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public void run() {
System.out.println("任務"+id+"開始運行,等待時間爲:"+delayMilliSecound);
}
}
//DelayQueue,存放Delayed元素的一個無界阻塞隊列,只有在某個元素的延遲期滿時才能從中提取元素,它和LinkedBlockingQueue不同的是,
//DelayQueue裏面哪怕有元素也無法取出,除非元素已經到期,也就是getDelay()返回值<=0;
//而LinkedBlockingQueue只要裏面有元素就可以取出!
//DelayQueue也可以看成是一個變相的優先級隊列;也就是說,越快失效的元素越能優先取出!
public static void delayQueue() throws InterruptedException{
final DelayQueue<DelayTask> queue = new DelayQueue<DelayTask>();
Random random = new Random();
for (int i = 0; i < 10; i++) {
queue.put(new DelayTask(random.nextInt(5000),i+1));
}
//開啓一個消費者線程消費隊列中的任務
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("開始消費隊列中的任務!");
while( !Thread.currentThread().isInterrupted()){
try {
//取出隊列中的元素
queue.take().run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//等任務全部消費完畢,再往隊列裏面塞一個ID爲100,延期3秒的任務!
TimeUnit.MILLISECONDS.sleep(6000);
queue.put(new DelayTask(3000, 100));
}
注意:DelayQueue中存放的對象必須實現Delayed接口的compareTo方法與getDelay方法!
看一下輸出:************************************************************************
開始消費隊列中的任務!
任務4開始運行,等待時間爲:554
任務9開始運行,等待時間爲:729
任務5開始運行,等待時間爲:917
任務3開始運行,等待時間爲:1079
任務1開始運行,等待時間爲:1652
任務10開始運行,等待時間爲:2969
任務2開始運行,等待時間爲:3676
任務7開始運行,等待時間爲:3829
任務6開始運行,等待時間爲:4252
任務8開始運行,等待時間爲:4294
任務100開始運行,等待時間爲:3000
**************************************************************************************
我們先往queue中塞入了十個DelayTask實例,且指定延時時間爲隨機5000毫秒內, 沒錯,一切都在我們的預料之中,延時時間越短的線程將先得到執行;