话不多说直接上代码:
public sealed class Singleton { private static Singleton _instance = null; // Creates an syn object. private static readonly object SynObject = new object(); Singleton() { } public static Singleton Instance { get { // Double-Checked Locking if (null == _instance) { lock (SynObject) { if (null == _instance) { _instance = new Singleton(); } } } return _instance; } } }
很久之前就看到这段代码,一直理解不了为啥要判断两次是否为空。刚刚画着图的时候突然就明白了,见下图:
假如上图还是没看明白的话,可以看下面一段没有两次判空的情况与上面作对比,如下:
public sealed class Singleton { private static Singleton _instance = null; // Creates an syn object. private static readonly object SynObject = new object(); Singleton() { } public static Singleton Instance { get { if (null == _instance) { lock (SynObject) { _instance = new Singleton(); } } return _instance; } } }
分析见下图:
看完上面先不要着急,再下面这段代码:
public sealed class Singleton { private static Singleton _instance = null; private static readonly object SynObject = new object(); Singleton() { } /// <summary> /// Gets the instance. /// </summary> public static Singleton Instance { get { lock (SynObject) { return _instance ?? (_instance = new Singleton()); } } } }
看到这里有些同学可能会产生疑问,如果像上面代码段进行一次判断也是可以实现多线程下单例的,为什么要判断两次呢?
这里我是这样理解的:线程安全的实现方式是要进行同步操作,那么我们可以降低通过操作的次数。而我们只需在同步操作之前,判断该实例是否为 null 就可以降低通过操作的次数了,这样就是经典的Double-Checked Locking了。