多线程下的单例-double check

时间:2021-07-01 07:09:05

话不多说直接上代码:

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;
        }
    }
}

很久之前就看到这段代码,一直理解不了为啥要判断两次是否为空。刚刚画着图的时候突然就明白了,见下图:

  多线程下的单例-double check

假如上图还是没看明白的话,可以看下面一段没有两次判空的情况与上面作对比,如下:

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;
        }
    }
}

分析见下图:

多线程下的单例-double check

看完上面先不要着急,再下面这段代码:

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了。