上篇博文《任務調度(三)——Timer的替代品ScheduledExecutorService簡介》已經對ScheduledExecutorService做了簡介。事實上使用ScheduledExecutorService來替代Timer也是迫不得已的事情。
主要原因例如以下:
- Timer不支持多線程。全部掛在Timer下的任務都是單線程的,任務僅僅能串行運行。假設當中一個任務運行時間過長。會影響到其它任務的運行,然后就可能會有各種接踵而來的問題。
- Timer的線程不捕獲異常。TimerTask假設拋出異常,那么Timer唯一的進程就會掛掉,這樣掛在Timer下的全部任務都會無法繼續運行。
第一個問題,隨着業務數據的猛增,我們生產上有幾個任務如今每次運行須要1-3個小時。在這段時間內,該timer下的其它任務僅僅能等待,這是讓人無法忍受的。重開一個Timer?難道要為全部的耗時的Task都單開一個Timer。顯然是不太可能。這樣就太亂了。
第二個問題。是極其致命的。
好多業務數據都是晚上的定時任務跑出來的。結果因為程序的問題或者內存資源不足,導致線程被kill了。該timer下的全部任務都未運行。結果第二天整整忙活了一天,主要任務就是——跑任務,調整數據。
深受其害呀!
為了彌補Timer的缺陷,jdk1.5中引入了並發包。這里面提供的ScheduledExecutorService。詳細實現類是:ScheduledThreadPoolExecutor。ScheduledThreadPoolExecutor支持多線程。同一時候在線程中對異常進行了捕獲。
所以是Timer的完美替換者。
分享一個實例吧:
/** * task2 * @author arron * @date 2015年8月5日 下午2:08:34 * @version 1.0 */ public class Task2 extends TimerTask{ @SuppressWarnings("deprecation") @Override public void run() { System.out.println("----task2 start--------"+new Date().toLocaleString()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("----5s later, task2 end--------"+new Date().toLocaleString()); } }測試代碼:
public static void main(String[] args) { ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);//啟用2個線程 Task1 t1 = new Task1(); // 馬上運行,任務消耗3秒。運行結束后等待2秒。【有空余線程時】,再次運行該任務 pool.scheduleWithFixedDelay(t1, 0, 2, TimeUnit.SECONDS); // 馬上運行,任務消耗5秒,運行結束后等待2秒。【有空余線程時】,再次運行該任務 Task2 t2 = new Task2(); pool.scheduleWithFixedDelay(t2, 0, 2, TimeUnit.SECONDS); }運行結果如圖:
這樣任務之間就不會相互影響了。並且能夠同一時候運行。可是線程數量要設置好了。
過渡添加線程數也會適得其反。