我移植了一些遗留代码并注意到某些类具有以下锁定对象:
protected readonly object _stateLock = Environment.TickCount;
对新对象()有什么好处吗? 我看到的另一个锁定对象是
private Nullable<int> _sLock = new Nullable<int>(Environment.TickCount);
使用它有什么好处吗?
答案 0 :(得分:4)
不,没有任何优势。 Environment.TickCount
和Nullable<int>
值都是值类型,并且会被装箱,即包装在新的object
引用中。
您的代码的第二个版本实际上更糟糕。第一个使用TickCount
的方法只是分配新object
引用的低效方法。但是引用永远不会改变,否则锁将正常工作。 lock
语句(或者更确切地说,基础Monitor
类)并不关心对象内部的值;它所关心的只是参考本身。所以装箱TickCount
,或17
或仅创建一个新object
,它们都是一样的。
使用Nullable<int>
的第二个版本是完全错误的,并且根本不会实现锁定行为。由于Nullable<int>
本身就是一种值类型,因此当任何代码尝试锁定该值时,即lock (_sLock)
,该值将在该时间点装箱,从而创建全新的object
引用只为那个锁。锁仅在需要共享数据的每个关键代码段也使用相同的object
引用进行锁定时才起作用。由于它们都将获得自己的新object
引用,因此根本不会发生同步。
我还应该指出编译器通常不允许你做第二个版本。即如果您尝试编译此代码,它将失败并显示错误:
Nullable<int> _sLock;
lock (_sLock) { }
错误将会读取
错误CS0185:&#39; int?&#39;不是lock语句
所要求的引用类型
如果你的代码实际上是按照你所说的那样编写的,那么编写代码的人可以通过转换_sLock
值来绕过这个非常有用的编译器错误,例如类似的东西:
lock ((object)_sLock) { }
如果我看到这样的代码,我会立即质疑编写代码的人的能力,并且会坚持审查他们触及的任何应该是线程安全的代码,看看他们搞砸了什么起来。