Timer與ScheduledExecutorService間的抉擇


java.util.Timer計時器有管理任務延遲執行("如1000ms后執行任務")以及周期性執行("如每500ms執行一次該任務")。
但是,Timer存在一些缺陷,因此你應該考慮使用ScheduledThreadPoolExecutor作為代替品,Timer對調度的支持是基於絕對時間,而不是相對時間的,
由此任務對系統時鍾的改變是敏感的;ScheduledThreadExecutor只支持相對時間。

Timer的另一個問題在於,如果TimerTask拋出未檢查的異常,Timer將會產生無法預料的行為。
Timer線程並不捕獲異常,所以TimerTask拋出的未檢查的異常會終止timer線程。
這種情況下,Timer也不會再重新恢復線程的執行了;它錯誤的認為整個Timer都被取消了。
此時,已經被安排但尚未執行的TimerTask永遠不會再執行了,新的任務也不能被調度了。
 
個人總結:timer的bug:60秒執行一次的話,如果用戶修改了時間的話 那么時針都會歸0,本來是臨近10秒執行的時候timer又會重新計時一次 再等60才執行。

 

測試Timer的例子

 1 package com.bill99.test;  
 2   
 3 import java.util.Timer;  
 4 import java.util.TimerTask;  
 5   
 6 public class TimerTest {  
 7     private Timer timer = new Timer();  
 8     //啟動計時器  
 9     public void lanuchTimer(){  
10         timer.schedule(new TimerTask(){  
11             public void run() {  
12                 throw new RuntimeException();  
13             }  
14         }, 1000*3, 500);  
15     }  
16     //向計時器添加一個任務  
17     public void addOneTask(){  
18         timer.schedule(new TimerTask(){  
19             public void run(){  
20                 System.out.println("hello world");  
21             }  
22         }, 1000*1,1000*5);  
23     }  
24       
25     public static void main(String[] args) throws Exception {  
26         TimerTest test = new TimerTest();  
27         test.lanuchTimer();  
28         Thread.sleep(1000*5);//5秒鍾之后添加一個新任務  
29         test.addOneTask();  
30     }  
31 }  

運行該程序,Timer會拋出一個RumtimeException和java.lang.IllegalStateException:Timer already cancelled.
常言道,真是禍不單行,Timer還將它的問題傳染給下一個倒霉的調用者,這個調用者原本試圖提交一個TimerTask的,你可能希望程序會一直運行下去,然而實際情況如程序所示5秒鍾后就中止了,還伴隨着一個異常,異常的消息是"Timer already cancelled"。ScheduledThreadPoolExector妥善地處理了這個異常的任務,所以說在java5.0或更高的JDK中,幾乎沒有理由再使用Timer了。

 

用ScheduledThreadPoolExector改進后的例子

 1 package com.bill99.test;  
 2   
 3 import java.util.concurrent.Executors;  
 4 import java.util.concurrent.ScheduledExecutorService;  
 5 import java.util.concurrent.TimeUnit;  
 6   
 7 public class ScheduledExecutorTest {  
 8     //線程池能按時間計划來執行任務,允許用戶設定計划執行任務的時間,int類型的參數是設定  
 9     //線程池中線程的最小數目。當任務較多時,線程池可能會自動創建更多的工作線程來執行任務  
10     //此處用Executors.newSingleThreadScheduledExecutor()更佳。
11     public ScheduledExecutorService scheduExec = Executors.newScheduledThreadPool(1);  
12     //啟動計時器  
13     public void lanuchTimer(){  
14         Runnable task = new Runnable() {  
15             public void run() {  
16                 throw new RuntimeException();  
17             }  
18         };  
19         scheduExec.scheduleWithFixedDelay(task, 1000*5, 1000*10, TimeUnit.MILLISECONDS);  
20     }  
21     //添加新任務  
22     public void addOneTask(){  
23         Runnable task = new Runnable() {  
24             public void run() {  
25                 System.out.println("welcome to china");  
26             }  
27         };  
28         scheduExec.scheduleWithFixedDelay(task, 1000*1, 1000, TimeUnit.MILLISECONDS);  
29     }  
30       
31     public static void main(String[] args) throws Exception {  
32         ScheduledExecutorTest test = new ScheduledExecutorTest();  
33         test.lanuchTimer();  
34         Thread.sleep(1000*5);//5秒鍾之后添加新任務  
35         test.addOneTask();  
36     }  
37 }  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM