前言
近期有個需求,要每隔一段時間,應用向背景發送一些資料,用作統計,這時可以使用Java提供的計時器的工具類,即Timer和TimerTask來實作這一功能。
簡介
Timer是一個普通的類,其中有幾個重要的方法;而TimerTask則是一個抽象類,其中有一個抽象方法run(),類似線程中的run()方法,我們使用Timer建立一個他的對象,然後調用schedule方法來完成這種間隔的操作。
這裡用到的這個schedule方法有三個參數:
第一個參數就是TimerTask對象,我們實作TimerTask的run()方法就是要周期執行的一個任務;
第二個參數是延遲執行的時間,有兩種類型,第一種是long類型,表示多長時間後開始執行,也就是說使用者調用 schedule() 方法後,要等待這麼長的時間才可以第一次執行run() 方法。另一種是Date類型,表示從那個時間後開始執行;
第三個參數就是執行的周期,為long類型,也就是說第一次調用之後,從第二次開始每隔多長的時間調用一次 run() 方法。
schedule方法還有一種兩個參數的執行重載,第一個參數仍然是TimerTask,第二個表示為long的形式表示多長時間後執行一次,為Date就表示某個時間後執行一次。
Java API:
//Schedules thespecified task for execution after the specifieddelay
schedule(TimerTask task, long delay)//在延時delay毫秒後執行task。并沒有提到重複執行
//Schedulesthe specified task for repeated fixed-delay execution, beginningafter the specified delay
schedule(TimerTask task, long delay, long period)//在延時delay毫秒後重複的執行task,周期是period毫秒。
Timer就是一個線程,使用schedule方法完成對TimerTask的排程,多個TimerTask可以共用一個Timer,也就是說Timer對象調用一次schedule方法就是建立了一個線程,并且調用一次schedule後TimerTask是無限制的循環下去的,使用Timer的cancel()停止操作。當然同一個Timer執行一次cancel()方法後,所有Timer線程都被終止。
另外Timer類還有一個排程方法scheduleAtFixedRate(),這個方法的參數與schedule()相同,具體的差別在下邊再說!
使用
//true 說明這個timer以daemon方式運作(優先級低,程式結束timer也自動結束)
Timer timer = new Timer(true);
TimerTask task = new TimerTask() {
public void run() {
//每次需要執行的代碼放到這裡面。
}
};
//以下是幾種排程task的方法:
//time為Date類型:在指定時間執行一次。
timer.schedule(task, time);
//firstTime為Date類型,period為long,表示從firstTime時刻開始,每隔period毫秒執行一次。
timer.schedule(task, firstTime, period);
//delay 為long類型:從現在起過delay毫秒執行一次。
timer.schedule(task, delay);
//delay為long,period為long:從現在起過delay毫秒以後,每隔period毫秒執行一次。
timer.schedule(task, delay, period);
兩種排程方法的差別
①啟動時間在指定時間之後(調用方法在設定的開始執行時間之後):
schedule()不會将過去的時間計算在内
SimpleDateFormat fTime = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date d1 = fTime.parse("2016/11/08 17:10:00");
timer.schedule(new TimerTask(){
public void run(){
System.out.println("this is task running");
}
},d1,**);
如果是在2016/11/08 17:20執行程式,則會在2016/11/08 17:23輸出第一條:this is task running
scheduleAtFixedRate()會将過去的時間計算在内
SimpleDateFormat fTime = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date d1 = fTime.parse("2016/11/08 17:10:00");
timer.scheduleAtFixedRate(new TimerTask(){
public void run(){
System.out.println("this is task running");
}
},d1,**);
如果是在2016/11/08 17:20執行程式,則會快速輸出三條:this is task running,第四條将會在2016/11/08 17:22輸出,而不是 17:23!就是說是從指定的開始時間開始計時,而不是從執行時間開始計時。
②任務延遲時的處理不同
schedule如果由于任何原因(如垃圾回收或其他背景活動)而延遲了某次執行,則後續執行也将被延遲。
schedule适用于那些需要“平穩”運作的重複活動。如以固定時間間隔閃爍的光标。
scheduleAtFixedRate如果由于任何原因(如垃圾回收或其他背景活動)而延遲了某次執行,則将快速連續地出現兩次或更多的執行,進而使後續執行能夠“追趕上來”。
scheduleAtFixedRate适用于那些對絕對時間敏感的重複執行活動,如每小時準點打鐘報時,或者在每天的特定時間運作已安排的維護活動。
題外話:
JDK 5.0以後推薦使用ScheduledThreadPoolExecutor,該類屬于Executor Framework,它除了能處理異常外,還可以建立多個線程解決上面的問題。
參考文章:
Java中的Timer和TimerTask在Android中的用法
Timer 的 schedule()方法
Timer類的schedule和scheduleAtFixedRate 簡單應用