这是我已经使用了几个月没有问题的代码。
public sealed class Singleton
{
private static Singleton value;
private static object syncRoot = new Object();
public static Singleton Value
{
get
{
if (Singleton.value == null)
{
lock (syncRoot)
{
if (Singleton.value == null)
{
Singleton.value = new Singleton();
}
}
}
return Singleton.value;
}
}
}
然而,我发现了这个链接,它概述了上述问题。
a) 写入Singleton.value = new Singleton();
可能会被处理器缓存,因此另一个线程可能无法看到它。为了解决这个问题,使用volatile
关键字。
Q(1): C#的lock
关键字不需要处理吗?
b) 在同一篇文章中,另一个更好的解决方案是避免使用volatile
,在写入Singleton.value
后引入System.Threading.Thread.MemoryBarrier();
。
问题:
Q(2) 我不太明白为什么需要在写操作之后使用MemoryBarrier()
。有哪些可能导致其他线程将Singleton.value
视为null的重新排序方式?lock
甚至可以阻止其他线程读任何内容。
Q(3) 屏障只会维护顺序,但如果值仍然从某些缓存中读取,还需要volatile
吗?
Q(4) 内存屏障是否真的需要在那里,因为C#的lock
本身就放置了它?
最后,
我需要更新我的代码采用哪种方法或者现有代码已经足够好了吗?
编辑
提出了使用Lazy
初始化的答案。我懂了。
但他们试图通过使用volatile和memorybarrier来实现lock不能保证的目标是什么?