在 .NET 中,System.Threading.Timer
和 System.Timers.Timer
都是用于定时任务的类,但它们的实现方式、使用场景和特性有所不同。以下是它们的 核心区别 和 使用示例:
1. System.Threading.Timer
特点
-
轻量级,基于线程池,适合高性能后台任务。
-
无事件机制,通过回调函数触发。
-
手动控制 启动/停止(通过
Change
方法)。 -
不直接支持 UI 操作(需手动切换线程)。
基本用法
using System;
using System.Threading;
class Program
{
static void Main()
{
// 创建定时器(回调函数,状态对象,初始延迟,间隔)
var timer = new Timer(
callback: state => Console.WriteLine($"触发时间: {DateTime.Now:T}"),
state: null,
dueTime: 1000, // 1秒后首次触发
period: 2000 // 之后每2秒触发一次
);
Console.ReadLine();
timer.Dispose(); // 释放资源
}
}
关键方法:
-
Change(dueTime, period)
:动态调整定时器(如暂停或重启)。 -
Dispose()
:释放定时器。
2. System.Timers.Timer
特点
-
基于事件(
Elapsed
事件),代码更易读。 -
支持自动重置(
AutoReset
属性控制是否循环)。 -
可绑定到 UI 线程(通过
SynchronizingObject
,仅 WinForms)。 -
适合需要事件机制的场景(如 UI 定时更新)。
基本用法
using System;
using System.Timers;
class Program
{
static void Main()
{
var timer = new System.Timers.Timer(interval: 1000); // 1秒间隔
timer.Elapsed += (sender, e) => Console.WriteLine($"触发时间: {e.SignalTime:T}");
timer.AutoReset = true; // 是否循环触发
timer.Start();
Console.ReadLine();
timer.Stop();
}
}
关键属性/方法:
-
Interval
:定时间隔(毫秒)。 -
AutoReset
:true
为循环触发,false
为单次触发。 -
Start()
/Stop()
:启停定时器。
3. 核心区别对比
特性 | System.Threading.Timer | System.Timers.Timer |
---|---|---|
命名空间 | System.Threading | System.Timers |
触发方式 | 回调函数 | Elapsed 事件 |
线程模型 | 线程池线程 | 默认线程池,可通过 SynchronizingObject 绑定到 UI 线程(WinForms) |
控制方法 | Change() 动态调整 | Start() / Stop() |
是否自动循环 | 由 period 参数决定 | 由 AutoReset 属性控制 |
适用场景 | 高性能后台任务 | 事件驱动任务(如 UI 更新) |
资源释放 | 需显式调用 Dispose() | 调用 Stop() 或 Dispose() |
4. 如何选择?
使用 System.Threading.Timer
当:
-
需要 轻量级、高性能 的后台轮询(如心跳检测)。
-
不需要直接操作 UI。
-
需要 灵活调整定时间隔(通过
Change
方法)。
使用 System.Timers.Timer
当:
-
需要 事件驱动 的代码结构(更易维护)。
-
在 WinForms 中更新 UI(通过
SynchronizingObject
)。 -
需要 简单的启停控制(
Start()
/Stop()
)。
5. 注意事项
共同点
-
默认在 后台线程 触发,直接操作 UI 会抛跨线程异常。
-
WPF 需用
Dispatcher.Invoke
。 -
WinForms 可用
Control.Invoke
或SynchronizingObject
(仅System.Timers.Timer
支持)。
-
System.Threading.Timer
的陷阱
-
回调中抛出异常会导致定时器 静默停止(需手动捕获异常)。
-
如果
period
设为Timeout.Infinite
,则只触发一次。
System.Timers.Timer
的陷阱
-
忘记设置
AutoReset = false
会导致无限循环。 -
不调用
Stop()
可能导致资源泄漏。
6. 完整示例(含 UI 操作)
WPF 中使用 System.Timers.Timer
更新 UI
// MainWindow.xaml.cs
using System.Timers;
using System.Windows;
public partial class MainWindow : Window
{
private readonly System.Timers.Timer _timer;
public MainWindow()
{
InitializeComponent();
_timer = new System.Timers.Timer(1000);
_timer.Elapsed += OnTimerElapsed;
_timer.Start();
}
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
// 必须通过 Dispatcher 更新 UI
Dispatcher.Invoke(() =>
{
TimeLabel.Content = $"当前时间: {e.SignalTime:T}";
});
}
protected override void OnClosed(EventArgs e)
{
_timer?.Dispose();
base.OnClosed(e);
}
}
控制台中使用 System.Threading.Timer
using System;
using System.Threading;
class Program
{
static void Main()
{
var timer = new Timer(
state => Console.WriteLine($"后台执行: {DateTime.Now:T}"),
null,
dueTime: 0,
period: 2000
);
Console.ReadLine();
timer.Dispose();
}
}
总结
-
简单后台轮询 →
System.Threading.Timer
(更高效)。 -
事件驱动/UI 操作 →
System.Timers.Timer
(更易用)。 -
始终记得释放资源(
Dispose()
或Stop()
)。