java.util.Timer計時器有管理工作順延強制("如1000ms後執行任務")以及周期性執行("如每500ms執行一次該任務")。但是,Timer存在一些缺陷,因此你應該考慮使用ScheduledThreadPoolExecutor作為代替品,Timer對調度的支援是基於絕對時間,而不是相對時間的,由此任務對系統時鐘的改變是敏感的;ScheduledThreadExecutor只支援相對時間。
Timer的另一個問題在於,如果TimerTask拋出未檢查的異常,Timer將會產生無法預料的行為。Timer線程並不捕獲異常,所以TimerTask拋出的未檢查的異常會終止timer線程。這種情況下,Timer也不會再重新恢複線程的執行了;它錯誤的認為整個Timer都被取消了。此時,已經被安排但尚未執行的TimerTask永遠不會再執行了,新的任務也不能被調度了。
- package com.bill99.test;
-
- import java.util.Timer;
- import java.util.TimerTask;
-
- public class TimerTest {
- private Timer timer = new Timer();
- //啟動計時器
- public void lanuchTimer(){
- timer.schedule(new TimerTask(){
- public void run() {
- throw new RuntimeException();
- }
- }, 1000*3, 500);
- }
- //向計時器添加一個任務
- public void addOneTask(){
- timer.schedule(new TimerTask(){
- public void run(){
- System.out.println("hello world");
- }
- }, 1000*1,1000*5);
- }
-
- public static void main(String[] args) throws Exception {
- TimerTest test = new TimerTest();
- test.lanuchTimer();
- Thread.sleep(1000*5);//5秒鐘之後添加一個新任務
- test.addOneTask();
- }
- }
運行該程式,Timer會拋出一個RumtimeException和java.lang.IllegalStateException:Timer already cancelled.
常言道,真是禍不單行,Timer還將它的問題傳染給下一個倒黴的調用者,這個調用者原本試圖提交一個TimerTask的,你可能希望程式會一直運行下去,然而實際情況如程式所示5秒鐘後就中止了,還伴隨著一個異常,異常的訊息是"Timer already cancelled"。ScheduledThreadPoolExector妥善地處理了這個異常的任務,所以說在java5.0或更高的JDK中,幾乎沒有理由再使用Timer了。
用ScheduledThreadPoolExector改進後的例子
- package com.bill99.test;
-
- import java.util.concurrent.Executors;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
-
- public class ScheduledExecutorTest {
- //線程池能按時間計劃來執行任務,允許使用者設定計劃執行任務的時間,int類型的參數是設定
- //線程池中線程的最小數目。當任務較多時,線程池可能會自動建立更多的背景工作執行緒來執行任務
- public ScheduledExecutorService scheduExec = Executors.newScheduledThreadPool(1);
- //啟動計時器
- public void lanuchTimer(){
- Runnable task = new Runnable() {
- public void run() {
- throw new RuntimeException();
- }
- };
- scheduExec.scheduleWithFixedDelay(task, 1000*5, 1000*10, TimeUnit.MILLISECONDS);
- }
- //添加新任務
- public void addOneTask(){
- Runnable task = new Runnable() {
- public void run() {
- System.out.println("welcome to china");
- }
- };
- scheduExec.scheduleWithFixedDelay(task, 1000*1, 1000, TimeUnit.MILLISECONDS);
- }
-
- public static void main(String[] args) throws Exception {
- ScheduledExecutorTest test = new ScheduledExecutorTest();
- test.lanuchTimer();
- Thread.sleep(1000*5);//5秒鐘之後添加新任務
- test.addOneTask();
- }
- }
- ScheduledExecutorService介面
在ExecutorService的基礎上,ScheduledExecutorService提供了按時間安排執行任務的功能,它提供的方法主要有:
schedule(task,initDelay):安排所提交的Callable或Runnable任務在initDelay指定的時間後執行。
scheduleAtFixedRate():安排所提交的Runnable任務按指定的間隔重複執行
scheduleWithFixedDelay():安排所提交的Runnable任務在每次執行完後,等待delay所指定的時間後重複執行。
代碼:ScheduleExecutorService的例子
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; public class ScheduledExecutorServiceTest
{
public static void main(String[] args) throws InterruptedException,ExecutionException
{
//*1
ScheduledExecutorService service=Executors.newScheduledThreadPool(2);
//*2
Runnable task1=new Runnable()
{
public void run()
{
System.out.println("Taskrepeating.");
}
};
//*3
final ScheduledFuture future1=service.scheduleAtFixedRate(task1,0,1,TimeUnit.SECONDS);
//*4
ScheduledFuture future2=service.schedule(new Callable()
{
public String call()
{
future1.cancel(true);
return "taskcancelled!";
}
},10,TimeUnit.SECONDS);
System.out.println(future2.get());
//*5
service.shutdown();
}
}
這個例子有兩個任務,第一個任務每隔一秒列印一句“Taskrepeating”,第二個任務在5秒鐘後取消第一個任務。