Timer
在應用開發中,經常需要一些周期性的操作,比如每5分鐘檢查一下新郵件等。對于這樣的操作最方便、高效的實現方式就是使用java.util.Timer工具類。比如下面的代碼每5分鐘檢查一遍是否有新郵件:
????????private?java.util.Timer?timer;
????????timer?=?new?Timer(true);
????????timer.schedule(new?java.util.TimerTask()?{
????????????public?void?run()?{
????????????????????//server.checkNewMail();?檢查新郵件
????????????}
????????},?0,?5*60*1000);
使用這幾行代碼之后,Timer本身會每隔5分鐘調用一遍server.checkNewMail()方法,不需要自己啟動線程。Timer本身也是多線程同步的,多個線程可以共用一個Timer,不需要外部的同步代碼。
????在《The?Java?Tutorial》中有更完整的例子:
public?class?AnnoyingBeep?{
????Toolkit?toolkit;
????Timer?timer;
????public?AnnoyingBeep()?{
????toolkit?=?Toolkit.getDefaultToolkit();
????????timer?=?new?Timer();
????????timer.schedule(new?RemindTask(),
???????????????????0,????????//initial?delay
???????????????????1*1000);??//subsequent?rate
????}
????class?RemindTask?extends?TimerTask?{
????int?numWarningBeeps?=?3;
????????public?void?run()?{
????????if?(numWarningBeeps?>?0)?{
????????????toolkit.beep();
????????System.out.println("Beep!");
????????numWarningBeeps--;
????????}?else?{
????????????toolkit.beep();?
????????????????System.out.println("Time's?up!");
????????????//timer.cancel();?//Not?necessary?because?we?call?System.exit
????????????System.exit(0);???//Stops?the?AWT?thread?(and?everything?else)
????????}
????????}
????}
????...
}
這段程序,每隔3秒響鈴一聲,并打印出一行消息。循環3次。程序輸出如下:
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
Timer類也可以方便地用來作為延遲執行,比如下面的代碼延遲指定的時間(以秒為單位)執行某操作。類似電視的延遲關機功能。
...
public?class?ReminderBeep?{
????...
????public?ReminderBeep(int?seconds)?{
????toolkit?=?Toolkit.getDefaultToolkit();
????????timer?=?new?Timer();
????????timer.schedule(new?RemindTask(),?seconds*1000);
????}
????class?RemindTask?extends?TimerTask?{
????????public?void?run()?{
????????????System.out.println("Time's?up!");
????????toolkit.beep();
????????//timer.cancel();?//Not?necessary?because?we?call?System.exit
????????System.exit(0);???//Stops?the?AWT?thread?(and?everything?else)
????????}
????}
????...
}
1.?有朋友來信問,希望自己的Task一直運行,而不是像上面的RemindTask那樣僅循環3次。
這很簡單,可能這位朋友把Task的作用理解有誤,Task僅代表了一次的動作。而不是讓Task完成循環。上面的RemindTask中之所以有一個計數,是因為要運行3次停止,如果需要一直保持運行。把上面有關的計數的代碼全部去除即可。其實Timer中并沒有提供運行指定次數后即停止的機制,所以,上面的計數滿足了這個功能需要。
2.?能否設置Timer的優先級?
Timer中是利用一個線程來進行計時及周期觸發動作的。現在的Timer實現中并沒有提供設置優先級的方法,在你調用new?Timer()時線程已經啟動,所以,除非Timer的以后版本中在構造方法中增加優先級參數,否則,我們是不能控制其優先級的。現在的Timer默認是在Thread.NORM_PRIORITY優先級下運行的。但是Timer提供了一個Timer(boolean?isDaemon)的構造方法,可以將Timer設置為daemon線程。這樣,在你的程序中其它線程都運行完畢后,程序就可以退出了。
3.?Timer是不是實現了精確地定時?
否。Timer中也是采用Object.wait(long?time)來實現定時的,由于Object.wait()不保證精確計時,所以Timer也不是一個精確的時鐘。如果是實時系統,不能依賴Timer。
4.?(liangyiqing)假如我在一個Timer類里面再定義一個Timer類,如果外層定義的時間是24小時循環一次,而內層定義的是1小時循環一次,意思就是當一個小時內層運行完一次之后,內層Timer釋放資源,我想問,外層的Timer是不是也會釋放,還是24小時之中一直都在占用?
我不太清楚你的占用資源是什么意思,如果你在Task中用到一些資源,這些資源應該在Task運行結束后即刻釋放,尤其對競態條件,更應該占用盡量少的時間。一般來說,一次Task的運行時間,將少于你設定的周期。否則,Task將在Timer中堆積起來。如果你要實現上面說的每24小時和每1小時兩個周期的操作,可以使用一個Timer,schedule兩個Task即可。
5.?Timer是否可以在多線程環境下使用?
可以。Timer中用于存儲Task的容器是同步了的,保證了多線程環境先的安全使用。
6.?(austin1979?)請問,定時的時間能為變量,可以在程序中變化嗎?就是說定時的時間可以又界面來控制。
一個Timer可以控制任意多個Task的不同周期設定的觸發。也就是說,這個Timer類似于可以定多個時間的鬧鐘,比如我的手機就有3個鬧鐘?:)??。但是一旦一個Task?已經進行了schedule了,那么就不能再次進行設定。所以,也不可能再改變其周期、延遲等等設定了。可以看下面的代碼:
????????????synchronized(task.lock)?{
????????????????if?(task.state?!=?TimerTask.VIRGIN)
????????????????????throw?new?IllegalStateException(
????????????????????????"Task?already?scheduled?or?cancelled");
????????????????task.nextExecutionTime?=?time;
????????????????task.period?=?period;
????????????????task.state?=?TimerTask.SCHEDULED;
????????????}
7.?(eqingtian)可不可以認為Timer就是一個線程的發射器?
?
Timer中僅有一個存儲Task的Queue和一個調度所有Task的線程。不管你schedule幾次,在Timer上加了幾個Task,都只有一個后臺的線程進行調度。
?
?
?
2014-11-12
總結
- 上一篇: net::ERR_INCOMPLETE_
- 下一篇: 在内部局域网(无外网)使用阿里云短信