.NET 中定时器的使用方法
在.NET 开发中,定时器是实现周期性任务的核心组件。根据是否依赖 UI 线程,可将其分为 “与 UI 无关联” 和 “与 UI 相关” 两大类,不同类型的定时器适用场景、线程模型及使用方式差异显著。本文将详细讲解各类定时器的特点、核心属性、正确用法及注意事项。
一、与 UI 无关联的定时器
此类定时器运行于非 UI 线程(默认使用线程池),适用于后台计算、数据同步等无需操作 UI 的场景,时间精度相对较高。
1. System.Timers.Timer
核心特点
关键属性修正
AutoReset:原始描述颠倒,正确逻辑为:
SynchronizingObject:默认值为null,任务运行于线程池(CPU 自动分配线程);若指定为 UI 控件(如 WinForms 的 Form),则任务会切换到 UI 线程执行。
Interval:任务执行间隔(单位:毫秒),最小值为 1。
Enabled:控制定时器是否启用(true启用,false禁用)。
正确代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| using System;
using System.Threading;
public class TimersTimerExample
{
// 声明定时器与线程同步锁(确保多线程安全)
private readonly System.Timers.Timer \_timer = new System.Timers.Timer();
private readonly object \_syncRoot = new object();
public TimersTimerExample()
{
// 绑定Elapsed事件(任务执行逻辑)
\_timer.Elapsed += OnTimerTick;
// 设置执行间隔为100毫秒
\_timer.Interval = 100;
// 配置为持续执行(AutoReset=true)
\_timer.AutoReset = true;
// 初始禁用,需手动启动
\_timer.Enabled = false;
}
// 启动定时器
public void StartTimer()
{
\_timer.Enabled = true;
// 或使用\_timer.Start()(与Enabled=true等效)
}
// 停止定时器
public void StopTimer()
{
\_timer.Enabled = false;
// 或使用\_timer.Stop()
}
// Elapsed事件回调(默认运行于线程池)
private void OnTimerTick(object sender, System.Timers.ElapsedEventArgs e)
{
// 加锁确保多线程下任务逻辑安全(避免并发问题)
lock (\_syncRoot)
{
Console.WriteLine(\$"后台任务执行:{DateTime.Now:HH:mm:ss.fff}");
// TODO:添加实际业务逻辑(如数据同步、日志记录)
}
}
}
|
注意事项
2. System.Threading.Timer
核心特点
关键参数
构造函数System.Threading.Timer(TimerCallback callback, object state, int dueTime, int period)参数说明:
callback:定时器触发时执行的回调函数;
state:传递给回调函数的参数(无需参数时设为null);
dueTime:定时器启动延迟时间(单位:毫秒),0表示立即启动;
period:任务执行间隔(单位:毫秒),Timeout.Infinite表示仅执行一次。
正确代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| using System;
using System.Threading;
public class ThreadingTimerExample
{
// 声明线程定时器(需注意释放资源)
private System.Threading.Timer \_timer;
public ThreadingTimerExample()
{
// 初始化定时器:立即启动(dueTime=0),间隔1000毫秒执行一次
\_timer = new System.Threading.Timer(
callback: TimerCallback,
state: null,
dueTime: 0,
period: 1000
);
}
// 定时器回调函数(运行于线程池)
private void TimerCallback(object state)
{
Console.WriteLine(\$"轻量级后台任务:{DateTime.Now:HH:mm:ss}");
// TODO:添加轻量级业务逻辑(如心跳检测、缓存清理)
}
// 释放定时器资源(避免内存泄漏)
public void DisposeTimer()
{
\_timer?.Change(Timeout.Infinite, Timeout.Infinite); // 先停止定时器
\_timer?.Dispose(); // 释放资源
}
}
|
注意事项
若任务执行时间超过period,线程池会分配新线程执行下一次任务,需自行控制并发;
不再使用时必须调用Dispose释放资源,避免线程泄漏;
无法直接更新 UI,需通过Dispatcher(WPF)或Invoke(WinForms)切换到 UI 线程。
二、与 UI 相关的定时器
此类定时器绑定 UI 线程,适用于 WinForms、WPF 等桌面应用的 UI 更新场景,无需手动处理线程安全,但时间精度较低(受 UI 线程繁忙程度影响)。
核心特点
仅适用于 WinForms 应用,支持可视化拖拽(从工具箱拖到 Form 上);
任务运行于 UI 线程,可直接更新 UI 控件(如 Label、TextBox);
精度较低(约 10-55 毫秒),不适用于高时效任务。
关键属性
Interval:执行间隔(单位:毫秒),最小值为 1;
Enabled:控制定时器启用 / 禁用(true启用,false禁用);
Tick:定时器触发时执行的事件(运行于 UI 线程)。
正确代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| using System;
using System.Windows.Forms;
public partial class TimerForm : Form
{
// 声明WinForms定时器(可通过设计器拖拽生成)
private readonly System.Windows.Forms.Timer \_uiTimer;
public TimerForm()
{
InitializeComponent();
// 初始化定时器(代码方式,非拖拽)
\_uiTimer = new System.Windows.Forms.Timer();
\_uiTimer.Interval = 1000; // 1秒更新一次UI
\_uiTimer.Tick += UITimer\_Tick;
\_uiTimer.Enabled = true; // 启用定时器
}
// Tick事件(运行于UI线程,可直接操作控件)
private void UITimer\_Tick(object sender, EventArgs e)
{
// 直接更新Label文本(无需线程同步)
lblTime.Text = \$"当前时间:{DateTime.Now:HH:mm:ss}";
}
// 关闭窗体时释放定时器
private void TimerForm\_FormClosing(object sender, FormClosingEventArgs e)
{
\_uiTimer?.Dispose();
}
}
|
注意事项
仅能在 WinForms 项目中使用,无法跨框架(如 WPF);
若Tick事件中执行耗时操作(如循环计算),会导致 UI 卡顿;
无需手动处理线程安全,因事件始终在 UI 线程执行。
2. System.Windows.DispatcherTimer(WPF 专用)
核心特点
仅适用于 WPF 应用,基于Dispatcher(WPF 线程调度器)实现;
任务运行于 UI 线程,支持直接更新 WPF 控件(如 TextBlock);
可通过DispatcherPriority调整任务优先级(默认Normal)。
关键属性与方法
Interval:执行间隔(类型:TimeSpan,支持秒、毫秒等单位);
Tick:定时器触发事件(运行于 UI 线程);
**Start()/Stop()**:启动 / 停止定时器(替代Enabled属性);
DispatcherPriority:任务在 UI 线程中的执行优先级(如Background表示后台优先级,不阻塞 UI)。
正确代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| using System;
using System.Windows;
using System.Windows.Threading;
public partial class MainWindow : Window
{
// 声明WPF调度定时器
private readonly DispatcherTimer \_dispatcherTimer;
public MainWindow()
{
InitializeComponent();
// 初始化定时器
\_dispatcherTimer = new DispatcherTimer();
// 设置间隔为1秒(使用TimeSpan)
\_dispatcherTimer.Interval = TimeSpan.FromSeconds(1);
// 绑定Tick事件
\_dispatcherTimer.Tick += DispatcherTimer\_Tick;
// 启动定时器
\_dispatcherTimer.Start();
}
// Tick事件(运行于UI线程,可直接更新WPF控件)
private void DispatcherTimer\_Tick(object sender, EventArgs e)
{
// 直接更新TextBlock内容
tbTime.Text = \$"当前时间:{DateTime.Now:HH:mm:ss.fff}";
}
// 关闭窗口时停止定时器
private void MainWindow\_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
\_dispatcherTimer?.Stop();
}
}
|
注意事项
仅能在 WPF 项目中使用,依赖System.Windows程序集;
若需降低任务对 UI 的影响,可设置_dispatcherTimer.DispatcherPriority = DispatcherPriority.Background;
若任务耗时较长,仍会导致 UI 响应缓慢,需结合Task开启后台线程处理(处理完后通过Dispatcher.Invoke更新 UI)。
三、定时器选择指南
| 定时器类型 |
适用框架 |
线程模型 |
精度 |
核心场景 |
| System.Timers.Timer |
通用(非 UI) |
线程池(可指定同步对象) |
较高 |
后台任务、数据同步 |
| System.Threading.Timer |
通用(非 UI) |
线程池 |
高 |
轻量级后台任务(如心跳检测) |
| System.Windows.Forms.Timer |
WinForms |
UI 线程 |
较低 |
WinForms UI 更新 |
| System.Windows.DispatcherTimer |
WPF |
UI 线程 |
较低 |
WPF UI 更新 |
总结:需根据项目框架(WinForms/WPF/ 控制台)、是否操作 UI、精度要求三大因素选择定时器,避免因线程模型不匹配导致 UI 卡顿或数据安全问题。
(注:文档部分内容可能由 AI 生成)