C#/.NET如何使用threading的Monitor实现无独占锁的特殊线程同步需求
你的需求可以实现,完全兼容当前Monitor的使用习惯,实现逻辑如下:
实现方案
你现有的线程1独占锁逻辑不需要做任何修改,仅需调整线程2的执行逻辑即可:
- 线程2优先调用
Monitor.TryEnter(lockObj, 0)无等待尝试获取锁,若获取成功说明当前无其他线程持有独占锁,直接释放锁后即可运行业务逻辑,符合你「无需获取独占锁即可运行」的要求 - 若
Monitor.TryEnter返回失败,说明当前有其他线程持有独占锁,此时调用阻塞式的Monitor.Enter等待锁释放,拿到锁后立即释放,即可开始运行业务逻辑
代码示例
// 公共锁对象,和线程1使用的是同一个实例 private static readonly object lockObj = new object(); // 线程1原有逻辑无需修改 void Thread1Logic() { bool lockTaken = false; try { Monitor.Enter(lockObj, ref lockTaken); // 线程1的独占业务逻辑 } finally { if (lockTaken) { Monitor.Exit(lockObj); } } } // 线程2适配逻辑 void Thread2Logic() { bool lockTaken = false; try { // 无等待尝试拿锁,判断当前是否存在独占锁 Monitor.TryEnter(lockObj, 0, ref lockTaken); if (!lockTaken) { // 存在其他线程的独占锁,阻塞等待锁释放 Monitor.Enter(lockObj, ref lockTaken); } // 立即释放锁,无需持有锁运行业务 } finally { if (lockTaken) { Monitor.Exit(lockObj); } } // 此处运行线程2的业务逻辑 }
注意事项
- 上述实现存在极短的时间窗口:锁释放到线程2业务逻辑执行的间隙,可能有其他线程再次获取到独占锁。如果你的业务场景不允许该间隙存在,仅需要把线程2的业务逻辑移到
try代码块内部、锁持有期间运行即可,线程2仅会持有锁极短时间,对原有线程1的逻辑影响可忽略不计。 - 所有
Monitor加锁操作必须配合finally块释放锁,避免出现异常时锁无法释放导致死锁。
内容的提问来源于stack exchange,提问作者Thomas Carlton
相关产品推荐
相关产品推荐

