java.util.Timer計時器有管理任務延遲執行("如1000ms后執行任務")以及周期性執行("如每500ms執行一次該任務")。但是,Timer存在一些缺陷,因此你應該考慮使用ScheduledThreadPoolExecutor作為代替品,Timer對調度的支持是基於絕對時間,而不是相對時間的,由此任務對系統時鍾的改變是敏感的;ScheduledThreadExecutor只支持相對時間。
Timer的另一個問題在於,如果TimerTask拋出未檢查的異常,Timer將會產生無法預料的行為。Timer線程並不捕獲異常,所以TimerTask拋出的未檢查的異常會終止timer線程。這種情況下,Timer也不會再重新恢復線程的執行了;它錯誤的認為整個Timer都被取消了。此時,已經被安排但尚未執行的TimerTask永遠不會再執行了,新的任務也不能被調度了。
public class OutOfTime { public static void main(String[] args) throws Exception { Timer timer = new Timer(); timer.schedule(new ThrowTask(), 1); SECONDS.sleep(1); timer.schedule(new ThrowTask(), 1); SECONDS.sleep(5); } static class ThrowTask extends TimerTask { public void run() { /*try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }*/ throw new RuntimeException(); } } }
執行結果
Exception in thread "Timer-0" java.lang.RuntimeException at net.jcip.examples.OutOfTime$ThrowTask.run(OutOfTime.java:31) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505) Exception in thread "main" java.lang.IllegalStateException: Timer already cancelled. at java.util.Timer.sched(Timer.java:397) at java.util.Timer.schedule(Timer.java:193) at net.jcip.examples.OutOfTime.main(OutOfTime.java:19)
Timer單線程執行任務,任務有可能丟失或執行時間不准確。
Timer執行任務時只是創建了單個線程。如果一個時間任務執行的時間比較長,那么其他任務執行時間的准確性就會受影響。比如每隔1秒執行一次任務,中間有個長任務執行時間超過5秒,那么在上一個任務執行完成時,會快速執行4次或者丟失任務。
public class OutOfTime { public static void main(String[] args) throws Exception { Timer timer = new Timer(); timer.schedule(new ThrowTask(), 1); SECONDS.sleep(1); timer.schedule(new ThrowTask(), 1); SECONDS.sleep(5); } static class ThrowTask extends TimerTask { public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } throw new RuntimeException(); } } }
執行結果
Exception in thread "Timer-0" java.lang.RuntimeException at net.jcip.examples.OutOfTime$ThrowTask.run(OutOfTime.java:31) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)