Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 带有双重检查锁的单例设计模式_C#_Design Patterns_Singleton - Fatal编程技术网

C# 带有双重检查锁的单例设计模式

C# 带有双重检查锁的单例设计模式,c#,design-patterns,singleton,C#,Design Patterns,Singleton,假设您有以下代码: 1.为什么我们使用双锁,为什么单锁不够好,请提供详细示例。 2.这种实现的主要缺点是什么?我该如何证明呢? 谢谢 获得一把锁是昂贵的。如果没有第一个if(s_Instance==null)检查,每次有人访问单例时都会获得一个锁。但是锁实际上只需要在实例创建期间存在。因此,第一个if(s_Instance==null)可以防止不必要的锁定。第二个if(s_Instance==null)需要在那里,因为最初两个线程可能会将第一个if(s_Instance==null)计算为tru

假设您有以下代码:
1.为什么我们使用双锁,为什么单锁不够好,请提供详细示例。
2.这种实现的主要缺点是什么?我该如何证明呢?
谢谢

  • 获得一把锁是昂贵的。如果没有第一个
    if(s_Instance==null)
    检查,每次有人访问单例时都会获得一个锁。但是锁实际上只需要在实例创建期间存在。因此,第一个
    if(s_Instance==null)
    可以防止不必要的锁定。第二个
    if(s_Instance==null)
    需要在那里,因为最初两个线程可能会将第一个
    if(s_Instance==null)
    计算为
    true
    ,然后两个线程将在锁内彼此实例化
    s_Instance
  • 我看不出您的实现中有任何真正的缺点,但使用替代方法(静态构造函数,见下文),我们有一个更简单、涉及代码更少的解决方案。因此,它更易于维护,更不容易出错。而且它根本不需要锁定。如前所述,锁定是昂贵的 您可以使用静态构造函数对其进行改进:

    public sealed class SomeSingleton5  
    {  
        // the compiler will generate a static constructor containing the following code 
        // and the CLR will call it (once) before SomeSingleton5 is first acccessed
        private static SomeSingleton5 s_Instance = new SomeSingleton5();
    
        private SomeSingleton5() { }
    
        public static SomeSingleton5 Instance
        {
            get
            {
                return s_Instance;
            }
        }
    }
    

    我认为单例类的最佳实现是由jonskeet提供的

    public sealed class Singleton
    {
      private static readonly Singleton instance = new Singleton();
      public static Singleton Instance { get { return instance; } }
      static Singleton() {}
      private Singleton() {}
    }
    


    这确实是最好的办法。不需要锁定。唯一的问题是,空白静态构造函数是必需的。+1静态初始化确实是一个非常有效的系统:)@Tilak:为什么需要空白静态构造函数?编辑:没关系,在链接中找到答案:)这是一种减轻beforefieldinit效应的简单方法。这是我的理解。我的理解可能不是100%正确,但它确实确保了行为的一致性。@Asif:谢谢,但关于我的实现,我们为什么要进行双重检查(ifX2),我真的不明白它的目的。在.NET中,您不必使用这种模式。类型系统保证静态字段不会受到双锁模式试图避免的竞争条件的影响。在Java中则不同。第二个检查是处理一个争用条件,在初始化
    s\u实例之前,两个线程都访问getter。两个线程都将
    s_实例
    计算为null,因此都将继续锁定。一个将进入,初始化
    s_实例
    并返回。第二个线程将进入,如果没有第二个检查,它将重新初始化
    s_实例
    ,并返回一个新实例。现在两个线程将有两个不同的单例实例。@ChrisSinclair:好吧,现在很清楚了,但我现在想知道这个解决方案是否完全解决了可能出现的任何竞争条件,或者我们刚刚解决了您提到的特定场景。我无法映射可能发生的所有争用条件,因此很难理解为什么这会解决所有争用条件。在
    锁中,运行时保证一次只能执行一个线程。因此,不可能有任何其他竞争条件。我能想到保留它的唯一原因是,如果您需要能够销毁/重新创建singleton实例。在这种情况下,您需要在destroy方法中镜像双重检查锁,并将其保存在singleton实例访问器中。谢谢,但是关于我的实现,我们为什么要进行双重检查(ifX2),我真的不明白它的目的
    
    public sealed class Singleton
    {
      private static readonly Singleton instance = new Singleton();
      public static Singleton Instance { get { return instance; } }
      static Singleton() {}
      private Singleton() {}
    }