一、Monitor核心概念
Monitor是.NET框架提供的线程同步工具,位于System.Threading命名空间。其通过内部锁机制实现对共享资源的有序访问,类似于交通信号灯控制多线程执行流程。
二、主要应用场景
- 保护临界区代码,防止并发修改共享数据结构
- 实现生产者-消费者模式等协调机制
- 提供比lock更灵活的显式同步控制
三、典型使用模式
1. 基础互斥访问
object syncRoot = new object();
bool lockTaken = false;
try
{
lockTaken = Monitor.TryEnter(syncRoot, 5000);
if (lockTaken)
{
// 执行临界区代码
}
}
finally
{
if (lockTaken) Monitor.Exit(syncRoot);
}
2. 等待通知机制
Queue<int> buffer = new Queue<int>();
object syncObj = new object();
void Consumer()
{
lock(syncObj)
{
while (buffer.Count == 0)
{
Monitor.Wait(syncObj);
}
int item = buffer.Dequeue();
Console.WriteLine($"消费数据: {item}");
}
}
void Producer()
{
lock(syncObj)
{
buffer.Enqueue(42);
Monitor.Pulse(syncObj);
}
}
四、关键注意事项
| 要点 | 说明 |
| 锁操作配对 | 必须成对使用Enter/Exit,建议使用try-finally保证释放 |
| Wait调用限制 | 必须在持有锁的状态下调用Wait方法 |
| 唤醒机制 | Pulse仅唤醒单个线程,PulseAll唤醒所有等待线程 |
| 死锁预防 | 避免嵌套锁竞争,防止循环等待 |
| 信号有效性 | Pulse在Wait前调用无效,需确保等待线程存在 |
五、与lock对比分析
| 特性 | lock | Monitor |
| 锁管理 | 自动加锁/解锁 | 需显式Enter/Exit |
| 等待通知 | 不支持 | 支持Wait/Pulse |
| 灵活性 | 仅限简单互斥 | 支持复杂同步场景 |
六、实际应用案例
| 场景 | 解决方案 |
| 数据写入防刷新 | 使用同步根对象+Enter/Exit |
| 生产消费模式 | Wait/Pulse实现协调通信 |
| 条件等待 | while(!condition) Wait()循环检测 |
七、高级用法
带超时的锁获取
object syncRoot = new object();
bool lockTaken = false;
try
{
lockTaken = Monitor.TryEnter(syncRoot, 5000);
if (lockTaken)
{
// 执行临界区代码
}
else
{
// 超时处理逻辑
}
}
finally
{
if (lockTaken) Monitor.Exit(syncRoot);
}
关键方法说明
- TryEnter(obj, timeout):尝试获取锁并设置超时时间
- Exit(obj):显式释放锁资源
- Pulse(obj):唤醒一个等待线程
- PulseAll(obj):唤醒所有等待线程