(在询问this related question 后,我仍有疑问。)
Lazy<T>
的整个想法(AFAIK)是在我们需要时创建对象 。
为什么?因为创建它很昂贵。
最后我想要的是Expensive
对象将被创建>1
次。
我不在乎许多线程最终会产生相同的引用。我只是不希望他们创建多个实例。
所以Lazyinitializer
通过syncLock
处理此问题:
LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive());
但是Lazy<T>
如何处理呢?
我在msdn中搜索过,无法找到任何syncLock
重载...
我错过了什么?
答案 0 :(得分:4)
你在问懒惰是如何在内部工作的吗?根据{{3}}:
,Lazy确保只创建一个默认情况下,Lazy对象是线程安全的。也就是说,如果构造函数 没有指定线程安全的种类,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调用。
答案 1 :(得分:3)
听起来你想要查看带有LazyThreadSafetyMode
的构造函数重载。
Lazy<T> lazy = new Lazy<T>(() => new T, LazyThreadSafetyMode.ExecutionAndPublication);
Lazy<T>
基本上是LazyInitializer
的用户友好版本,单线程或多线程init的确切实现隐藏在该枚举后面。