進階篇:延時隊列之DelayQueue(十四)

這篇文章我們來講講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毫秒內,   沒錯,一切都在我們的預料之中,延時時間越短的線程將先得到執行;


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