關於Timer和TimerTask

Timer 功能在指定的時間間隔內反覆觸發指定視窗的定時器事件。下面yjbys小編為大家準備了關於Timer和TimerTask的文章,歡迎閱讀。

關於Timer和TimerTask

  1.概覽

Timer是一種定時器工具,用來在一個後臺執行緒計劃執行指定任務。它可以計劃執行一個任務一次或反覆多次。

TimerTask一個抽象類,它的子類代表一個可以被Timer計劃的任務。

簡單的一個例程:

import r;

import rTask;

/**

* Simple demo that uses r to schedule a task to execute

* once 5 seconds have passed.

*/

public class Reminder {

Timer timer;

public Reminder(int seconds) {

timer = new Timer();

dule(new RemindTask(), seconds*1000);

}

class RemindTask extends TimerTask {

public void run() {

tln("Time's up!");

el(); //Terminate the timer thread

}

}

public static void main(String args[]) {

tln("About to schedule task.");

new Reminder(5);

tln("Task scheduled.");

}

}

執行這個小例子,你會首先看到:

About to schedule task.

5秒鐘之後你會看到:

Time's up!

這個小例子可以說明一些用Timer執行緒實現和計劃執行一個任務的基礎步驟:

實現自定義的TimerTask的子類,run方法包含要執行的任務程式碼,在這個例子裡,這個子類就是RemindTask。

例項化Timer類,建立計時器後臺執行緒。

例項化任務物件 (new RemindTask()).

制定執行計劃。這裡用schedule方法,第一個引數是TimerTask物件,第二個引數表示開始執行前的延時時間(單位是milliseconds,這裡定義了5000)。還有一種方法可以指定任務的執行時間,如下例,指定任務在11:01 p.m.執行:

//Get the Date corresponding to 11:01:00 pm today.

Calendar calendar = nstance();

(_OF_DAY, 23);

(TE, 1);

(ND, 0);

Date time = ime();

timer = new Timer();

dule(new RemindTask(), time);

  2.終止Timer執行緒

預設情況下,只要一個程式的timer執行緒在執行,那麼這個程式就會保持執行。當然,你可以通過以下四種方法終止一個timer執行緒:

呼叫timer的cancle方法。你可以從程式的任何地方呼叫此方法,甚至在一個timer task的run方法裡。

讓timer執行緒成為一個daemon執行緒(可以在建立timer時使用new Timer(true)達到這個目地),這樣當程式只有daemon執行緒的時候,它就會自動終止執行。

當timer相關的所有task執行完畢以後,刪除所有此timer物件的引用(置成null),這樣timer執行緒也會終止。

呼叫方法,使整個程式(所有執行緒)終止。

Reminder的例子使用了第一種方式。在這裡不能使用第二種方式,因為這裡需要程式保持執行直到timer的任務執行完成,如果設成daemon,那麼當main執行緒結束的時候,程式只剩下timer這個daemon執行緒,於是程式不會等timer執行緒執行task就終止了。

有些時候,程式的終止與否並不只與timer執行緒有關。舉個例子,如果我們使用AWT來beep,那麼AWT會自動建立一個非daemon執行緒來保持程式的執行。

import r;

import rTask;

import kit;

/**

* Simple demo that uses r to schedule a task to execute

* once 5 seconds have passed.

*/

public class ReminderBeep {

Toolkit toolkit;

Timer timer;

public ReminderBeep(int seconds) {

toolkit = efaultToolkit();

timer = new Timer();

dule(new RemindTask(), seconds*1000);

}

class RemindTask extends TimerTask {

public void run() {

tln("Time's up!");

();

//el(); //Not necessary because we call

(0); //Stops the AWT thread (and everything else)

}

}

public static void main(String args[]) {

tln("About to schedule task.");

new ReminderBeep(5);

tln("Task scheduled.");

}

}

  3.反覆執行一個任務

先看一個例子:

public class AnnoyingBeep {

Toolkit toolkit;

Timer timer;

public AnnoyingBeep() {

toolkit = efaultToolkit();

timer = new Timer();

dule(new RemindTask(),

0, //initial delay

1*1000); //subsequent rate

}

class RemindTask extends TimerTask {

int numWarningBeeps = 3;

public void run() {

if (numWarningBeeps > 0) {

();

tln("Beep!");

numWarningBeeps--;

} else {

();

tln("Time's up!");

//el(); //Not necessary because we call

(0); //Stops the AWT thread (and everything else)

}

}

}

...

}

執行,你會看到如下輸出:

Task scheduled.

Beep!

Beep! //one second after the first beep

Beep! //one second after the second beep

Time's up! //one second after the third beep

這裡使用了三個引數的'schedule方法用來指定task每隔一秒執行一次。如下所列為所有Timer類用來制定計劃反覆執行task的方法 :

schedule(TimerTask task, long delay, long period)

schedule(TimerTask task, Date time, long period)

scheduleAtFixedRate(TimerTask task, long delay, long period)

scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

當計劃反覆執行的任務時,如果你注重任務執行的平滑度,那麼請使用schedule方法,如果你在乎的是任務的執行頻度那麼使用scheduleAtFixedRate方法。 例如,這裡使用了schedule方法,這就意味著所有beep之間的時間間隔至少為1秒,也就是說,如果有一個beap因為某種原因遲到了(未按計劃執行),那麼餘下的所有beep都要延時執行。如果我們想讓這個程式正好在3秒以後終止,無論哪一個beep因為什麼原因被延時,那麼我們需要使用scheduleAtFixedRate方法,這樣當第一個beep遲到時,那麼後面的beep就會以最快的速度緊密執行(最大限度的壓縮間隔時間)。

  4.進一步分析schedule和scheduleAtFixedRate

(1)2個引數的schedule在制定任務計劃時, 如果指定的計劃執行時間scheduledExecutionTime<=systemCurrentTime,則task會被立即執行。scheduledExecutionTime不會因為某一個task的過度執行而改變。

(2)3個引數的schedule在制定反覆執行一個task的計劃時,每一次執行這個task的計劃執行時間隨著前一次的實際執行時間而變,也就是scheduledExecutionTime(第n+1次)=realExecutionTime(第n次)+periodTime。也就是說如果第n次執行task時,由於某種原因這次執行時間過長,執行完後的systemCurrentTime>=scheduledExecutionTime(第n+1次),則此時不做時隔等待,立即執行第n+1次task,而接下來的第n+2次task的scheduledExecutionTime(第n+2次)就隨著變成了realExecutionTime(第n+1次)+periodTime。說白了,這個方法更注重保持間隔時間的穩定。

(3)3個引數的scheduleAtFixedRate在制定反覆執行一個task的計劃時,每一次執行這個task的計劃執行時間在最初就被定下來了,也就是scheduledExecutionTime(第n次)=firstExecuteTime+n*periodTime;如果第n次執行task時,由於某種原因這次執行時間過長,執行完後的systemCurrentTime>=scheduledExecutionTime(第n+1次),則此時不做period間隔等待,立即執行第n+1次task,而接下來的第n+2次的task的scheduledExecutionTime(第n+2次)依然還是firstExecuteTime+(n+2)*periodTime這在第一次執行task就定下來了。說白了,這個方法更注重保持執行頻率的穩定。

  5.一些注意的問題

每一個Timer僅對應唯一一個執行緒。

Timer不保證任務執行的十分精確。

Timer類的執行緒安全的。