C#懒惰初始化&&比赛到初始化?

时间:2012-07-19 07:20:18

标签: c# .net multithreading .net-4.0

关于LazyInitializerreading表示:

  

它提供了另一种具有多个线程的初始化模式   竞争初始化。

这是一个示例:

Expensive _expensive;
public Expensive Expensive
     {
       get // Implement double-checked locking
         {
           LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());
           return _expensive;
         }
     }

问题#1

看着: enter image description here

为什么#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个线程进入:

enter image description here

昂贵的物品将被创造两次!

再次,3个问题

1)为什么#A说它实现了双重检查锁定?这只是一个获得的优势?

2)#B(l​​ambda表达式)是否是线程安全的?

3)初始化不是线程安全的竞争

1 个答案:

答案 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()只会被调用一次。