单一模式中的双重检查锁定

Rag*_*v55 20 c#

这可能是基本问题

要在多线程环境中使用单例,我们可以使用锁.请参阅代码段.但为什么我们需要在单件模式中进行双重检查锁定?更多的双重锁定意味着什么?

class singleton
{
    private static singleton instance = null;
    private static singleton() { }

    private static object objectlock = new object();

    public static singleton Instance
    {
        get
        {

            lock (objectlock) //single - check lock
            {
                if (instance == null)
                {
                    instance = new singleton();
                }

                return instance;
            }
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

SLa*_*aks 27

Jon Skeet 详细解释了这一点.

锁是昂贵的.
如果对象已经存在,那么取出锁是没有意义的.
因此,您可以在锁外进行第一次检查.

但是,即使在您查看之前该对象不存在,另一个线程也可能在if条件和lock语句之间创建它.
因此,您需要在锁内再次检查.

但是,编写单例的最佳方法是使用static构造函数:

public sealed class Singleton
{
    private Singleton()
    {
    }

    public static Singleton Instance { get { return Nested.instance; } }

    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton();
    }
} 
Run Code Online (Sandbox Code Playgroud)

  • 我找到了不使用此解决方案的原因;如果发生异常,您的客户端将看到嵌套在 TypeInitializationException 中的异常,这将使其不那么明显。因此我回到双重检查锁定解决方案(Jon Skeet 解决方案 3) (2认同)

小智 6

多线程单例:使用双重检查锁定的最佳方法

public sealed class Singleton
{
   private static volatile Singleton _instance;
   private static readonly object InstanceLoker= new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (_instance == null) 
         {
            lock (InstanceLoker) 
            {
               if (_instance == null) 
                  _instance = new Singleton();
            }
         }

         return _instance;
      }
   }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

使用.Net 4.x和更新版本时,您应尽可能遵循Lazy类,因为此模式与"初始化和发布"选项一起使用.(注意:逆也可用,其中创建不是线程安全的,但实例的发布是通过Publication选项发布的)