2 回答
TA贡献2021条经验 获得超8个赞
当您要在一个线程中处理一个类中的多个变量时,是否应该为要锁定在该类中的每个变量都拥有一个“锁定对象”?
有两个规则:
要“细粒度”。拥有尽可能多的锁,每个变量一个。每次使用它时,都应在其锁下访问变量。锁定尽可能少的代码以确保可伸缩性。如果忘记锁定变量,则会导致争用情况;如果锁定顺序错误,则会导致死锁,因此请确保其完美无缺。
要“粗粒度”。仅拥有一个锁,然后将所有关键部分放在该锁下。拥有多个锁可以减少争用,但会增加死锁和其他错误的可能性,因此锁应尽可能少,每个锁中要包含尽可能多的代码。当然,这也增加了死锁的风险,因为现在锁中有很多代码可以进行倒置,并且降低了可伸缩性。
毫无疑问,标准建议是完全矛盾的。那是因为锁很糟糕。
我的建议:如果您不跨线程共享变量,则根本不需要任何锁。
这也是处理线程安全自定义类型的有效方法吗?
到目前为止,代码看起来还算合理,但是如果您打算延迟加载某些逻辑,则不要编写自己的线程逻辑。只需使用Lazy<T>
并使其起作用即可。它是由专家撰写的。
始终使用专家提供的最高级工具。滚动自己的线程原语是灾难的根源。
无论您采取什么措施,都不要采纳另一个答案中的建议,即您必须使用双重检查锁定。有没有什么情况下,你必须使用双重检查锁定。单次检查锁定更安全,更容易且更可能正确。仅在以下情况下使用双重检查锁定:(1)您有大量的经验证据表明争用是可衡量的,影响用户的性能问题的原因,该问题将通过低锁定得到解决,并且(2)您可以解释C#内存模型使双重检查锁定变得安全。
如果您不能执行(1),那么您就没有理由进行双重检查锁定;如果您不能执行(2),则不能放心任何安全性。
TA贡献1785条经验 获得超8个赞
您需要使用双重检查的锁定模式。初始化someClass之后,无需获取someClassLock锁,将其锁定在那只会导致不必要的争用。
if (someClass == null)
{
lock(someClassLock)
{
if (someClass == null)
someClass = new SomeClass();
}
}
您需要内部if块,因为并发线程可能在第一次空检查之后但在获取锁之前创建了someClass。
当然,您还需要确保以某种本身是线程安全的方式编写SomeClass,但这将安全地确保仅创建someClass的一个实例。
另一种方法是使用Lazy<T>合适的LazyThreadSafetyMode。
- 2 回答
- 0 关注
- 199 浏览
添加回答
举报