关于LazyInitializer
后reading表示:
它提供了另一种具有多个线程的初始化模式 竞争初始化。
这是一个示例:
Expensive _expensive;
public Expensive Expensive
{
get // Implement double-checked locking
{
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());
return _expensive;
}
}
问题#1
看着:为什么#A说它实现了双重检查锁定?这只是一个获得的优势?
问题#2
#B(lambda表达式)是否是线程安全的?
问题#3
所以我通过查看样本搜索了这个“竞赛初始化”的事情:
volatile Expensive _expensive;
public Expensive Expensive
{
get
{
if (_expensive == null)
{
var instance = new Expensive();
Interlocked.CompareExchange (ref _expensive, instance, null);
}
return _expensive;
}
}
然后我想到:isnt race to initialize是线程安全的吗?
e / g /如果有2个线程进入:
昂贵的物品将被创造两次!
再次,3个问题
1)为什么#A说它实现了双重检查锁定?这只是一个获得的优势?
2)#B(lambda表达式)是否是线程安全的?
3)初始化不是线程安全的竞争
答案 0 :(得分:5)
EnsureInitialized
存在各种重载。有些人接受synclock
对象(可以是null
,并且将由EnsureInitialized
方法创建)。其他人没有synclock
作为参数。所有EnsureInitialized
保证如果在对象未初始化时由两个(或更多)不同线程同时调用,则两个线程将接收对同一对象的引用。所以:
Expensive _expensive;
// On thread 1
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());
// On thread 2
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());
两个线程将看到的_expensive
对象将是相同的。
唯一的问题是new Expensive()
可以被调用两次(每个线程一次,所以在多线程竞赛中它可以被调用更多次。)
如果您不需要,请使用synclock
重载:
Expensive _expensive;
object _sync = null;
bool _useless;
// On thread 1
LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive());
// On thread 2
LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive());
现在,对于运行的两个(或更多)线程的每个可能组合,new Expensive()
只会被调用一次。