1、System.Threading.Timer 线程计时器
1、最底层、轻量级的计时器。基于线程池实现的,工作在辅助线程。
2、它并不是内在线程安全的,并且使用起来比其他计时器更麻烦。此计时器通常不适合 Windows 窗体环境。
构造函数:public Timer(TimerCallback callback, object state, int dueTime, int period);
1
2
3
4
5
6
7
8
|
string state=”.”; //state参数可以传入想在callback委托中处理的对象。可以传递一个AutoRestEvent,在回调函数中向主函数发送信号。 Timer timer= new Timer(TimeMethod,state,100,1000) //100表示多久后开始,1000表示隔多久执行一次。 void TimerMethod( object state) {Console.Write(state.ToString());} timer.Dispose(); //取消timer执行 |
2、System.Timers.Timer 服务器计时器
1、针对服务器的服务程序,基于System.Threading.Timer,被设计并优化成能用于多线程环境。在这种情况下,应该确保事件处理程序不与 UI 交互。在asp.net中一般使用System.Timers.Timer。
2、继承自Compnent,公开了可以SynchronizingObject 属性,避免了线程池中无法访问主线程中组件的问题(模拟System.Windows.Forms.Timer单线程模式)。但是除非需要对事件的时间安排进行更精确的控制,否则还是应该改为使用 System.Windows.Forms.Timer。
3、AutoReset属性设置计时器是否在引发Elapsed事件后重新计时,默认为true。如果该属性设为False,则只执行timer_Elapsed方法一次。
4、System.Timers.Timer是多线程定时器,如果一个Timer没有处理完成,到达下一个时间点,新的Timer同样会被启动。所以,Timer比较适合执行不太耗时的小任务,若在Timer中运行耗时任务,很容易出现由于超时导致的多线程重入问题,即多个线程同时进入timer_Elapsed方法。
1
2
3
4
5
6
7
8
9
10
|
System.Timers.Timer timer = new System.Timers.Timer(); timer.Interval = 500; timer.SynchronizingObject = this ; timer.Elapsed+= new System.Timers.ElapsedEventHandler(timer_Elapsed); timer.Start(); private void timer_Elapsed(Object source, Timers.ElapsedEventArgs e) { this .tbTimer.Text = value; } |
5、为了应对多线程重入问题。可以加锁,也可以增加标志位。 Interlocked.Exchange提供了一种轻量级的线程安全的给对象赋值的方法,所以使用Interlocked.Exchange给变量赋值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
int inTimer = 0; void timer_Elapsed( object sender, System.Timers.ElapsedEventArgs e) { if (Interlocked.Exchange( ref inTimer, 1) == 0) { Thread.Sleep(3000); string currentThreadId = Thread.CurrentThread.ManagedThreadId.ToString(); this .Dispatcher.BeginInvoke( new Action(() => { this .Label_Result.Content += currentThreadId + "," ; }), null ); Interlocked.Exchange( ref inTimer, 0); } } |
3、System.Windows.Forms.Timer Windows计时器
此计时器直接继承自Component,它经过了专门的优化以便与 Windows 窗体一起使用,并且必须在窗口中使用。
- Windows计时器建立在基于消息的UI线程上运行,精度限定为5ms。Tick事件中执行的事件与主窗体是同一个线程(单线程),并且对与 UI 交互是安全的。
- 只有Enable和Internal两个属性和一个Tick事件,可以使用Start()和Stop()方法控制Enable属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
using System.Windows.Forms; public Form1() { InitializeComponent(); this .Load += delegate { Timer timer = new Timer(); timer.Interval = 500; timer.Tick += delegate { System.Diagnostics.Debug.WriteLine($ "Timer Thread: {System.Threading.Thread.CurrentThread.ManagedThreadId}" ); System.Diagnostics.Debug.WriteLine($ "Is Thread Pool: {System.Threading.Thread.CurrentThread.IsThreadPoolThread}" ); this .lblTimer.Text = DateTime.Now.ToLongTimeString(); }; timer.Start(); System.Diagnostics.Debug.WriteLine($ "Main Thread: {System.Threading.Thread.CurrentThread.ManagedThreadId}" ); }; } |
4. System.Windows.Threading.DispatcherTimer
主要用于WPF中。属性和方法与System.Windows.Forms.Timer类似。DispatcherTimer中Tick事件执行是在主线程中进行的。
使用DispatcherTimer时有一点需要注意,因为DispatcherTimer的Tick事件是排在Dispatcher队列中的,当系统在高负荷时,不能保证在Interval时间段执行,可能会有轻微的延迟,但是绝对可以保证Tick的执行不会早于Interval设置的时间。如果对Tick执行时间准确性高可以设置DispatcherTimer的priority。
Austin Liu 刘恒辉
Project Manager and Software Designer E-Mail:lzhdim@163.com Blog:https://lzhdim.cnblogs.com 欢迎收藏和转载此博客中的博文,但是请注明出处,给笔者一个与大家交流的空间。谢谢大家。 |