C#Lazy Initialization && Race-to-initialize?
在阅读了LazyInitializer
,它是:
它提供了另一种初始化模式,它有多个线程竞争初始化。
这是一个示例:
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)初始化的不竞争是线程安全的
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()
可以被调用两次(每个线程一次,所以在multithreading竞争中它可以被调用更多次。)
如果您不想要它,请使用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()
将仅被调用一次。