在.Net Framework Class Library(FCL)中,System.Threading命名空間下定義了一個Timer類,這就是常用的一個計時器。實際上FCL總共提供了如下幾種計時器:
在實際的開發中,這個類出現和使用頻率非常高,下面就重點談談它的一些基礎概念和應用實例。
(1)、常用的構造器
1
public
Timer(TimerCallback callback,
object
state,
int
dueTime,
int
period);
2
public
Timer(TimerCallback callback,
object
state,
long
dueTime,
long
period);
3
public
Timer(TimerCallback callback,
object
state, TimeSpan dueTime, TimeSpan period);
4
public
Timer(TimerCallback callback,
object
state,
uint
dueTime,
uint
period);
參數說明:
a、callback:望文生意,肯定表示一個回調,它是標識希望由一個線程池線程回調的方法。當然它的類型必須和System.Threading.TimerCallback委托類型匹配,如下所示:
1
public
delegate
void
TimerCallback(
object
state);
b、state:每次調用回調方法,向回調方法傳遞的狀態數據,如沒有,可以為null;
c、dueTime:在首次調用回調方法之前要等待多少毫秒。如希望立刻調用回調方法,該參數指定為0即可。
d、period:指定了以後每次調用回調方法之前要等待多少毫秒(理解成下一次和本次調用的時間間隔即可)。如果為該參數傳遞Timeout.Infinite(或者直接寫-1),線程池線程只調用回調方法一次(那也就沒有必要用計時器了)。
(2)、基本工作原理
在內部(原文應該指CLR內),線程池為所有Timer對象只使用了一個線程。這個線程知道下一個Timer對象在什麼時候到期(計時器還有多久觸發)。下一個Timer對象到期時,線程就會喚醒,在內部調用ThreadPool的QueueUserWorkItem,將一個工作項添加到線程池的隊列中,使你的回調方法得到調用。
注意:如果回調方法的執行時間很長,計時器可能在上個回調還沒有完成的時候再次觸發(對於執行時間很長的任務,實際開發中通常不使用線程池,而是直接使用new一個Thread)。這可能會造成多個線程池線程同時調用你的方法(方法的重疊覆蓋?)。為了解決這個問題,Jeffrey Richter建議我們這樣使用Timer:
a、為period指定Timeout.Infinite。這樣,計時器就只觸發一次;
b、在回調方法中,調用Timer的Change方法來指定一個新的dueTime,並再次為period指定Timeout.Infinite。Change方法的幾個重載版本:
1
public
bool
Change(
int
dueTime,
int
period);
2
3
public
bool
Change(
long
dueTime,
long
period);
4
5
public
bool
Change(TimeSpan dueTime, TimeSpan period);
6
7
public
bool
Change(
uint
dueTime,
uint
period);
Timer還有一個Dispose方法,允許完全取消計時器。
(3)、示例代碼