我有两个使用延迟加载支持字段的内部属性,并且在多线程应用程序中使用,因此我按照this MSDN article实现了一个双重检查锁定方案
现在,首先假设这是一个合适的模式,所有示例都显示为实例创建单个锁对象。如果我的两个属性彼此独立,那么为每个属性创建一个锁实例会不会更有效?
我觉得可能只有一个是为了避免死锁或竞争条件。一个明显的情况不会浮现在脑海中,但我相信有人可以给我看一个...(我对多线程代码的经验不是很明显)
private List<SomeObject1> _someProperty1;
private List<SomeObject2> _someProperty2;
private readonly _syncLockSomeProperty1 = new Object();
private readonly _syncLockSomeProperty2 = new Object();
internal List<SomeObject1> SomeProperty1
{
get
{
if (_someProperty1== null)
{
lock (_syncLockSomeProperty1)
{
if (_someProperty1 == null)
{
_someProperty1 = new List<SomeObject1>();
}
}
}
return _someProperty1;
}
set
{
_someProperty1 = value;
}
}
internal List<SomeObject2> SomeProperty2
{
get
{
if (_someProperty2 == null)
{
lock (_syncLockSomeProperty2)
{
if (_someProperty2 == null)
{
_someProperty2 = new List<SomeObject2>();
}
}
}
return _someProperty2;
}
set
{
_someProperty2 = value;
}
}
答案 0 :(得分:3)
如果您的属性真正独立,那么为每个属性使用独立锁都没有坏处。
答案 1 :(得分:1)
如果两个属性(或更具体的初始值设定项)彼此独立,就像您提供的示例代码一样,有两个不同的锁定对象是有意义的。但是,当初始化很少发生时,效果可以忽略不计。
请注意,您也应该保护setter的代码。 lock
语句强加了一个所谓的内存屏障,这对于防止竞争条件的多CPU和/或多核系统尤其必不可少。
答案 2 :(得分:0)
是的,如果它们彼此独立,这确实会更有效率,因为访问一个不会阻止访问另一个。如果这种独立性证明是错误的,那么你也可以获得有关僵局风险的资金。
问题是,假设_someProperty1 = new List<SomeObject1>();
不是分配给_someProperty1
的真实代码(几乎不值得延迟加载,是吗?),那么问题是:代码可以吗填充SomeProperty1曾经通过任何代码路径调用填充SomeProperty2的内容,反之亦然,无论多么奇怪?
即使一方可以呼叫另一方,也不会出现死锁,但如果两方都可以互相呼叫(或1呼叫2,2呼叫3和3呼叫1,依此类推),则死锁可以肯定会发生。
作为一项规则,我首先使用广泛的锁(一个锁用于所有锁定的任务)然后根据需要使锁更窄作为优化。如果您有20个需要锁定的方法,那么判断安全性会更困难(同样,您只需使用锁定对象开始填充内存)。
请注意,您的代码也有两个问题:
首先,你没有锁定你的二传手。可能这很好(你只是希望你的锁可以防止多次调用加载方法,并且实际上并不关心set
和get
之间是否存在重写),可能这是一场灾难。
其次,根据运行它的CPU,在写入时仔细检查可能会出现读/写重新排序问题,因此您应该有一个volatile字段,或者调用内存屏障。见http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx
编辑:
还值得考虑是否真的需要它。
考虑操作本身应该是线程安全的:
1和2只发生在一个线程上,3是原子的。因此,锁定的优点是:
如果执行上面的步骤1和/或2有自己的线程问题,并且没有通过自己的锁保护它们,那么锁定是100%必要的。
如果对步骤1和2中获得的值采取行动并且稍后重复步骤1和2进行操作将是灾难性的,则锁定是100%必需的。
锁定可防止多次浪费1和2。
因此,如果我们可以排除案例1和案例2作为一个问题(需要进行一些分析,但这通常是可能的),那么我们只能防止案例3中的浪费担心。现在,也许这是一个很大的担忧。但是,如果它很少出现,并且也没有那么多浪费,那么不锁定的收益将超过锁定的收益。
如果有疑问,锁定可能是更安全的方法,但它可能只是偶尔浪费的操作生活更好。