在.NET中双重检查locking
我遇到这篇文章,讨论为什么在Java中打破了双重检查locking范例。 是范例有效的.NET(特别是C#),如果variables被宣布为volatile
?
在C#中实现Singleton模式在第三个版本中讨论了这个问题。
它说:
让实例variablesvolatile可以使其工作,就像明确的内存屏障调用一样,但是在后一种情况下,即使是专家也不能确切地同意需要哪些屏障。 我倾向于避免专家不同意正确和错误的情况!
作者似乎暗示双重locking比其他策略更不可能工作,因此不应该被使用。
双重检查锁现在可以在Java和C#中工作(Java内存模型已更改,这是其中一个效果)。 但是,你必须完全正确。 如果你把事情搞得一团糟,你最终可能会失去线程的安全性。
正如其他答案所述,如果你正在实施单例模式 ,有更好的方法来做到这一点。 就个人而言,如果我处于必须在双重lockinglocking和“每次locking”代码之间进行select的情况,那么我会每次lockinglocking,直到有确实的证据certificate它正在造成瓶颈。 说到线程,一个简单而明显正确的模式是值得的。
.NET 4.0有一个新的types: Lazy<T>
,它带走了任何关于获取模式错误的担心。 它是新的任务并行库的一部分。
请参阅MSDN并行计算开发人员中心: http : //msdn.microsoft.com/en-us/concurrency/default.aspx
顺便说一下,这里有一个可用的.NET 3.5 SP1的backport(我相信这是不受支持的)。
注意比在Java中(也很可能在.Net中),对单例初始化的双重检查locking是完全不必要的,也是破坏的。 由于类在第一次使用之前没有被初始化,因此已经实现了所需的延迟初始化。
private static Singleton instance = new Singleton();
除非你的Singleton类包含像在第一次使用Singleton实例之前可以访问的常量那样的东西,这就是你所需要做的。
我已经通过使用一个布尔值(即使用一个基元来避免懒惰的初始化)重新检查locking工作:
使用布尔值的单例不起作用。 除非您经历内存障碍,否则不能保证不同线程之间的操作顺序。 换句话说,从第二个线程看, created = true
可以在instance= new Singleton();
之前执行instance= new Singleton();
我不明白为什么有一大堆的双重locking实现模式(显然是为了解决各种语言的编译器特质)。 关于这个主题的维基百科文章显示了天真的方法和可能的方法来解决这个问题,但没有像这样简单(在C#中):
public class Foo { static Foo _singleton = null; static object _singletonLock = new object(); public static Foo Singleton { get { if ( _singleton == null ) lock ( _singletonLock ) if ( _singleton == null ) { Foo foo = new Foo(); // Do possibly lengthy initialization, // but make sure the initialization // chain doesn't invoke Foo.Singleton. foo.Initialize(); // _singleton remains null until // object construction is done. _singleton = foo; } return _singleton; } }
在Java中,您将使用synchronized()而不是lock(),但它基本上是一样的想法。 如果单个字段被赋值时可能出现不一致,那么为什么不先使用一个本地作用域的variables,然后在退出临界区之前的最后一个时刻分配单个字段呢? 我错过了什么吗?
有一个@ michael-borgwardt的观点认为,在C#和Java中,静态字段只在第一次使用时被初始化,但是这种行为是特定于语言的。 我经常使用这种模式来进行集合属性的懒化初始化(例如user.Sessions)。
我不明白为什么所有的人都说双重locking是坏模式,但不适应代码使其正常工作。 在我看来,这下面的代码应该工作得很好。
如果有人能告诉我,如果这个代码遭受了卡梅隆文章中提到的问题,请做。
public sealed class Singleton { static Singleton instance = null; static readonly object padlock = new object(); Singleton() { } public static Singleton Instance { get { if (instance != null) { return instance; } lock (padlock) { if (instance != null) { return instance; } tempInstance = new Singleton(); // initialize the object with data instance = tempInstance; } return instance; } } }
我已经通过使用一个布尔值(即使用一个基元来避免懒惰的初始化)重新检查locking工作:
private static Singleton instance; private static boolean created; public static Singleton getInstance() { if (!created) { synchronized (Singleton.class) { if (!created) { instance = new Singleton(); created = true; } } } return instance; }