

新闻资讯
技术学院lock是Monitor的语法糖,编译后完全等价于Monitor.Enter+try-finally+Monitor.Exit;它自动确保异常时释放锁,但不支持超时、Wait/Pulse等高级功能。
你写 lock(obj) { ... },编译器立刻把它翻译成 Monitor.Enter + try-finally + Monitor.Exit。不是“类似”,是**完全等价**——IL 层面一模一样。所以别纠结“哪个更底层”,lock 不是替代品,它是 Monitor 的安全封装。
try-finally,哪怕临界区抛异常,锁也必释放(不用你操心)当你不确定锁会不会被长时间占用(比如依赖外部服务、数据库慢查询、或另一个可能卡住的线程),用 Monitor.TryEnter(obj, timeout) 是唯一靠谱的选择。它返回 bool:成功拿到锁就干正事,失败就走降级逻辑,而不是傻等。
timeout 单位是毫秒,传 0 表示“试试看,不等”;传 -1 等价于无限等待(和 Monitor.Enter 一样)Monitor.Exit,且只能在 lockTaken == true 时调用,否则抛 SynchronizationLockException
finally 里检查 lockTaken,直接 Monitor.Exit → 运行时报错bool lockTaken = false;
try
{
if (Monitor.TryEnter(_syncObj, 500)) // 等最多 500ms
{
lockTaken = true;
// 执行临界区
}
else
{
Log.Warn("获取锁超时,跳过处理");
return;
}
}
finally
{
if (lockTaken) Monitor.Exit(_syncObj);
}
如果你在写生产者-消费者、信号量控制、状态驱动的协同逻辑(比如“等数据来了再处理”),lock 直接出局。Monitor.Wait 会**主动释放锁并挂起当前线程**,直到另一个线程调用 Monitor.Pulse 或 Monitor.PulseAll 唤醒它——这是协作式同步的核心机制。
Wait 必须在已持有锁的前提下调用,否则抛 SynchronizationLockException
Pulse 只唤醒一个等待线程;PulseAll 唤醒全部——但唤醒不等于立即执行,它们还得重新竞争锁Pulse 后 Wait(即“信号丢失”),必须用循环条件检查 + while 包裹 Wait
无论用哪个,锁对象本身出问题,同步就形同虚设。最常见三类雷:
this:
外部代码可能也锁你实例,引发意外阻塞typeof(MyClass) 或字符串字面量:跨 Assembly 或 intern 字符串共享,锁范围远超预期public object SyncRoot):别人改了它,你的 Monitor.Exit 就找不到原锁对象正确做法永远是:private readonly object _syncObj = new object(); —— 它只属于你,不可变,不暴露。
Monitor 提供能力,lock 提供安全底线;该用哪个,不看“高级感”,而看有没有 Wait/Pulse 或超时需求。其余时候,老老实实写 lock,少一行代码,少一个 bug。