System.Threading命名空间定义了一个Timer类,其作用让一个线程池线程定时调用一个方法。构造Timer类的实例相当于告诉线程池:在将来某个时间回调你的一个方法。
一、Timer类
注释:
callback参数:标识希望由一个线程池线程回调的方法
state参数:允许在每次调用回调方法时都向它传递状态数据
duetime参数:告诉CLR在首次调用回调方法之前要等待多少毫秒
period参数:指定了以后每次调用回调方法之前要等待多少毫秒,如果为这个参数传递Timeout.Infinite(-1),线程池线程则只 调用回调方法一次
在内部,线程池为所有Timer对象只使用了一个线程。这个线程知道下一个Timer对象在什么时候触发(计时器还有多久触发)。下一个Timer对象到期时,线程就会唤醒,在内部调用ThreadPool的QueueUserWorkItem,将下一个工作项添加到线程池的队列中,使你的回调方法得到调用。如果回调方法的执行时间很长,计时器可能(在上个回调还没有完成的时候)再次触发。这可能造成多个线程池同时执行你的回调方法。解决办法是:为period参数指定Timeout.Infinite,这样,计时器就只触发一次。然后,在你的回调方法中,调用Change方法来指定一个新的dueTime,并再次为period参数指定Timeout.Infinite。
Timer类中的Dispose方法,允许完全取消计时器,并可在当时处于pending状态的所有回调完成之后,向notifyObject参数标识的内核对象发出信号。
using System.Collections.Generic;
using System;
using System.Threading.Tasks;
using System.Threading;
public static class Example
{
private static Timer s_timer;
public static void Main()
{
Console.WriteLine("checking status every 2 seconds");
//创建但不启动计时器。确保s_timer在线程调用Status之前引用该计时器
s_timer = new Timer(Status, null, Timeout.Infinite, Timeout.Infinite);
//现在s_timer已被赋值,可以启动计时器了
//现在在Status中调用change,保证不会抛出NullReferenceException
s_timer.Change(0, Timeout.Infinite);
Console.ReadLine();
}
/// <summary>
/// 方法的签名必须和TimerCallBack委托匹配
/// </summary>
/// <param name="state"></param>
public static void Status(object state)
{
//这个方法由一个线程池线程执行
Console.WriteLine("In Status at {0}", DateTime.Now);
Thread.Sleep(1000);
//返回前让Timer在2秒后再次触发
s_timer.Change(2000, Timeout.Infinite);
//这个方法返回后,线程回归线程池中,等待下一个工作项
}
}