lock 和 Mutex 的本质区别在哪?
lock是 C# 关键字,底层直接调用
Monitor.Enter和
Monitor.Exit,纯托管、无系统调用;
Mutex是 Windows 内核对象(.NET 封装),每次
WaitOne/
ReleaseMutex都会触发用户态 → 内核态切换。这意味着:
•
lock只能在**同一进程内**的线程间同步
•
Mutex可跨进程、跨 AppDomain,甚至能被其他语言(如 C++)创建的进程识别
性能差距有多大?实际测出来才信
在单进程多线程场景下,
lock比
Mutex快一个数量级。实测(
0xFFFFF ≈ 1048575次临界区进入):
•
lock:约
1335 ms
•
Mutex:通常在
10000+ ms量级(取决于系统负载)
原因不是“Mutex 写得差”,而是每次等待都得进内核——哪怕锁立刻可用,也要走一遍上下文切换开销。
private void TestWithLock(int times)
{
for (int i = 0; i < times; i++)
{
lock (_lockObj) { Acc(i); }
}
}
<p>private void TestWithMutex(int times)
{
for (int i = 0; i < times; i++)
{
_mutex.WaitOne(); // 这里就已进内核
try { Acc(i); }
finally { _mutex.ReleaseMutex(); }
}
}什么时候非用 Mutex 不可?
只有当你要解决**跨进程竞争**时才需要
Mutex,例如:
• 多个独立 EXE 程序共用同一个本地数据库文件(需确保写入互斥)
• Windows 服务 + 桌面客户端共享配置缓存文件
• 单实例应用(通过命名
Mutex检测是否已有进程运行)
其他所有情况——包括 ASP.NET 请求处理、后台任务队列、内存缓存更新——都该用
lock或
Monitor。 别用
lock(this)或
lock(typeof(MyClass)):容易引发外部死锁 别把
int、
string当锁对象:
string有字符串驻留,
int会装箱成不同对象,导致锁失效
Mutex创建时若传入名称(如
new Mutex(false, "MyApp.GlobalLock")),它就变成全局内核对象,必须注意权限和释放——忘了
ReleaseMutex会导致其他进程永久阻塞
Monitor 能不能替代 Mutex?
不能。
Monitor和
lock一样,只作用于当前进程内的线程;它比
lock多出
TryEnter(可设超时防死锁)、
Wait/
Pulse(线程协作),但依然**不跨进程**。如果你只是想避免
lock无法超时的问题,用
Monitor.TryEnter(obj, timeout)即可,无需升格到
Mutex。
真正该警惕的,不是“选错锁”,而是“根本不需要锁”——比如只读静态数据、每个线程独享的局部变量、或已被
ConcurrentDictionary等线程安全集合封装的操作。加锁是手段,不是目的。
