C#多线程同步利器:Monitor全解析
C#多线程同步利器:Monitor全解析
- 一、Monitor是什么
- 二、Monitor 用在什么场景?这两类场景必用
- 三、实战Demo:3个示例掌握Monitor核心用法
-
- 示例1:基础用法——Enter/Exit 的 “标准姿势”
- 示例2:进阶用法——用TryEnter避免“无限等待”
- 示例3:高级用法——生产者-消费者模型(Wait/Pulse实战)
- 四、Monitor 核心方法速查表(建议收藏)
- 五、避坑指南
- 总结:Monitor的“核心价值”
C#多线程同步利器:Monitor全解析
多线程编程中,共享资源的并发访问常引发数据混乱。而C#的 Monitor 就像一把精准的安全锁,能让多线程 “有序排队”,是保障数据一致性的基础工具,也是编写稳健多线程程序的必备知识
一、Monitor是什么
Monitor是C#提供的线程同步工具类,核心作用只有一个:保证同一时刻只有一个线程能访问“共享资源”。如果把共享资源比作 “单人间”,Monitor 就是房间的 “门锁”:
- 线程要进房间(访问资源),必须先拿钥匙(获取 Monitor 的 “锁”)
- 拿到钥匙的线程在房间里时(执行临界区代码),其他线程只能在门外排队(阻塞等待)
- 线程离开房间后(完成操作),必须把钥匙还回来(释放锁),下一个排队的线程才能进去
这种“互斥访问”的机制,就是Monitor解决线程安全问题的核心逻辑。更重要的是,它还有Wait/Pulse这样的 “进阶技能”,能实现线程间的“协作”—— 让线程按需等待或唤醒,应对更复杂的同步场景
二、Monitor 用在什么场景?这两类场景必用
Monitor的价值,在“多线程操作共享资源”和“线程间需配合”时最突出,这两类场景几乎是多线程开发的 “高频考点”:
- 共享资源的互斥访问,避免数据错乱
- 多个线程要读写同一份数据(比如计数器、缓存、配置项)。若不做同步,极易出现“数据覆盖”或“结果错乱”
- 用Monitor(或其语法糖lock)锁定“读-改-写”的过程,能确保同一时间只有一个线程操作,避免这类问题
- 线程间的有序协作,按需等待与唤醒
- 当线程需要“互相配合”时,Wait/Pulse是关键
- 最经典的就是 “生产者 - 消费者模型”:生产者生成数据后,要通知消费者来处理;消费者没数据时,需等待生产者的通知。实现“按需等待、即时响应”,避免线程空转浪费资源,效率大幅提升
三、实战Demo:3个示例掌握Monitor核心用法
示例1:基础用法——Enter/Exit 的 “标准姿势”
- Monitor 最基础的用法是 “获取锁 - 执行临界区 - 释放锁”,对应 Enter 和 Exit 方法。注意必须 “成对出现”,且释放锁要放在 finally 里(防异常导致锁没释放)
//创建一个用于线程同步的共享对象
//readonly 确保该对象在初始化后不会被重新赋值,避免同步失效
private static readonly object _lockObj = new object();
static void MonitorEnterExitDemo()
{Monitor.Enter(_lockObj); // 获取锁,进入临界区,此时其他线程若尝试获取该锁,将被阻塞try{// 临界区代码}finally{// 离开临界区,释放锁:无论try里是否抛异常,都能确保锁被释放Monitor.Exit(_lockObj); }
}
- 小提示:若只是简单的 “锁 - 执行 - 放”,更推荐使用lock语句——它本质是
Monitor.Enter+try-finally+Monitor.Exit
的语法糖,代码更简洁,且能避免手动释放锁的疏漏 一文读懂 C# 中的 lock:多线程编程的“安全锁”
示例2:进阶用法——用TryEnter避免“无限等待”
lock
和Monitor.Enter
有个问题:若拿不到锁,线程会一直阻塞Monitor.TryEnter
更灵活:会“尝试”拿锁,拿不到就返回false,还能设置“超时时间”,适合不希望线程无限等待的场景
private static readonly object _lockObj = new object();
static void MonitorTryEnterExitDemo()
{bool lockTaken = false; // 标记是否成功拿到锁try<