关于C#中Timers.Timer类多定时器使用的三个技术问题
关于C# Timers.Timer的三个问题解答
问题1:在定时器事件触发前重新执行m_Timer = new Timer(...)会产生什么结果?
- 原Timer对象会失去引用,但它的回调仍可能触发:定时器由线程池调度,只要未被Dispose,即便你已无引用,到触发时间回调依然会执行。
- 旧定时器变成“无主”状态:你无法再控制它(停止、Dispose),只能等待GC回收,这会造成不必要的资源占用,甚至引发逻辑错误(比如旧回调在新定时器创建后仍执行,干扰当前业务逻辑)。
问题2:C#是否有内置方法处理这种情况?需要用List管理吗?
- 单个定时器场景无需用List,直接利用
IDisposable接口即可:Timers.Timer实现了IDisposable,创建新定时器前,先对旧定时器执行Dispose操作,就能安全清理资源并停止回调。修正后的示例代码:
public void MyEventNotification(in MyEventInfo ei) { if (ei.State != MyEventState.Completed) { // 先清理旧定时器 m_Timer?.Dispose(); // 注意:ei.StringID无需new,直接传递即可 m_Timer = new Timer(TimerHandler, ei.StringID, 1000, Timeout.Infinite); } }
- 仅当需要同时管理多个独立定时器时,才需要用集合(比如
List<Timer>)跟踪,此时要注意线程安全,清理时需遍历集合对每个定时器执行Dispose。
问题3:将定时器加入List后,能否在TimerHandler中移除自身?
- 可以,但必须注意线程安全:Timer的回调在ThreadPool线程执行,若添加/移除List的操作在其他线程(比如调用
MyEventNotification的线程)同时进行,会引发线程冲突。 - 正确实现方式:
- 使用线程安全集合,比如
ConcurrentBag<Timer>,它自带线程安全的添加/移除方法; - 若用普通
List<Timer>,需在操作List时加lock保护; - 移除前先Dispose当前定时器,避免后续回调触发。示例代码:
- 使用线程安全集合,比如
// 定义锁对象和List private readonly object _timerLock = new object(); private List<Timer> _timerList = new List<Timer>(); public void TimerHandler(Object stateinfo) { string id = (string)stateinfo; // 加锁操作List,确保线程安全 lock (_timerLock) { var currentTimer = _timerList.FirstOrDefault(t => /* 根据stateinfo或标识匹配当前定时器 */); if (currentTimer != null) { currentTimer.Dispose(); _timerList.Remove(currentTimer); } } }
额外代码修正提示
- 原代码中
new ei.StringID是错误写法,直接传ei.StringID即可(它本身已是字符串类型); - 访问
m_JustForShow时要注意线程安全:若该字段会被多线程(主线程、定时器回调线程)修改/读取,需用volatile修饰或加lock,避免内存可见性问题。
内容的提问来源于stack exchange,提问作者user3161924
相关产品推荐
相关产品推荐

