2012-12-02 30 views
3

询问this related question后,我仍然有一个问题。C#懒惰<T>&Race-to-initialize?

整个想法(据我所知)与Lazy<T>,是创建对象只有当我们需要它。 为什么?因为创造它是昂贵的。

最后事情我想要的是,Expensive对象将被创建>1次。

我不在乎是否许多线程最终会产生相同的参考。我只是不希望他们创建多个实例。

所以Lazyinitializer处理这个由syncLock

LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync,() => new Expensive()); 

但如何能Lazy<T>处理呢? 我在MSDN中搜索并没有找到任何syncLock过载...

我错过了什么?

回答

4

你在问懒惰是如何在内部工作的吗?懒惰确实保证只有一个将被创建,按照MSDN documentation

默认情况下,惰性对象是线程安全的。也就是说,如果构造函数 未指定线程安全类型,则它创建的Lazy对象是线程安全的。在多线程场景中,访问线程安全的Lazy对象的Value属性的第一个线程 将为所有线程上的所有后续访问初始化为 ,并且所有线程共享 相同的数据。因此,哪个线程初始化对象,竞争条件是否良好并不重要。

如果你实际上问它的内部工作原理,它似乎是使用某种类型的lock

 object obj = Volatile.Read<object>(ref this.m_threadSafeObj); 
     bool flag = false; 
     try 
     { 
      if (obj != Lazy<T>.ALREADY_INVOKED_SENTINEL) 
      { 
       Monitor.Enter(obj, ref flag); 
      } 
      if (this.m_boxed == null) 
      { 
       boxed = this.CreateValue(); 
       this.m_boxed = boxed; 
       Volatile.Write<object>(ref this.m_threadSafeObj, Lazy<T>.ALREADY_INVOKED_SENTINEL); 
      } 
      else 
      { 
       boxed = (this.m_boxed as Lazy<T>.Boxed); 
       if (boxed == null) 
       { 
        Lazy<T>.LazyInternalExceptionHolder lazyInternalExceptionHolder = this.m_boxed as Lazy<T>.LazyInternalExceptionHolder; 
        lazyInternalExceptionHolder.m_edi.Throw(); 
       } 
      } 
     } 
     finally 
     { 
      if (flag) 
      { 
       Monitor.Exit(obj); 
      } 
     } 

通知的Monitor.Enter和Monitor.Exit调用。

+0

虽然它使用监视器,但它不会这样做,我会称之为“简单”方式。 –

+0

注意:)更新.... – BFree

3

听起来就像你想看看构造函数重载,它需要一个LazyThreadSafetyMode

Lazy<T> lazy = new Lazy<T>(() => new T, LazyThreadSafetyMode.ExecutionAndPublication); 

Lazy<T>基本上是LazyInitializer一个用户友好的版本,与具体实现的单或多线程的init被隐藏的枚举后面。

+0

wt *?是否很难添加像在LazyInitializer中创建的syncobj? –

+0

带'ExecutionAndPublication'的'懒惰'相当于带有'syncLock'的'LazyInitializer'。你只会得到一个实例。 –

+0

@罗伊常常不在乎某件事是否“很难”(尽管这可能是一个因素) - 它是:是否需要?它有用吗?我猜这两个失败了。 Lazy-T中的监视器用法很微妙。 –