lock 能不能用在 struct 类型上?
不能。C# 编译器会直接报错:
CS0185: 'lock' statement operand must be of a reference type。因为
lock的参数必须是引用类型,而
struct是值类型。
为什么 struct 会被拒绝?根本原因是什么
不是编译器“故意刁难”,而是语义上完全失效:
struct每次传给
lock都会触发装箱(boxing),生成一个**新的、独立的对象实例** —— 每个线程锁的其实是不同的对象,根本起不到互斥作用; 即使你写成
lock(myStruct),实际等价于
lock((object)myStruct),每次装箱都 new 一个新
object,锁对象不唯一,同步失效; 更危险的是:这种代码看似能编译(某些旧版编译器可能静默允许,但行为不可靠),实则埋下隐蔽的竞态 bug,极难复现和调试。
常见误用场景与正确替代方案
有人试图用
struct作锁来“节省内存”或“避免 new object”,这是典型误解。真正安全且轻量的做法只有一种:
private static readonly object _lock = new object(); // ✅ 推荐:静态、只读、专用
<p>// 错误示例(编译不过):
// private readonly MyStruct _lockStruct = new MyStruct();
// lock(_lockStruct) { ... } // ❌ CS0185</p><p>// 危险示例(看似能跑,实则无效):
// var s = new MyStruct();
// lock((object)s) { ... } // ❌ 每次 boxing 都是新对象,锁不住</p>如果需要保护某个
struct字段(如
Point、
DateTime),请把它封装进类中,再用私有
object字段加锁: 不要锁
this、
typeof(T)、字符串字面量(如
"mylock"); 不要锁 public 或可变对象(比如某个 List 实例,外部可能被替换); 若需高性能,考虑
Interlocked原子操作(适用于简单整数/引用赋值)或
ConcurrentDictionary等无锁集合。
一句话收尾
struct 不是“不够格”,而是它天生不具备锁所需的对象身份一致性 —— 锁的本质是“同一个引用”,而 struct 的每次传递都在悄悄换人。别绕弯子,老老实实用
private static readonly object。
