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(l​​ambda表达式)是否是线程安全的?

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()将仅被调用一次。