【问题标题】:Difference between these two Singleton implementations这两个 Singleton 实现之间的区别
【发布时间】:2012-02-29 01:50:59
【问题描述】:

我正在学习如何实现一些基本的设计模式。在学习单例模式时,我注意到网络上有两种常见的实现:

// Possibly from: http://www.yoda.arachsys.com/csharp/singleton.html
// I cannot remember exact source, sorry :(

public sealed class Singleton
{
    // Static members are 'eagerly initialized', that is,
    // immediately when class is loaded for the first time.
    // .NET guarantees thread safety for static initialization
    private static readonly Singleton instance = new Singleton();

    // Private constructor prevents instantiation from other classes
    private Singleton() { }

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    public static Singleton() { }

    // Get the instance of the singleton
    public static Singleton getInstance()
    {
            return instance;
    }

}

和:

public class Singleton
{
  // Static, VOLATILE variable to store single instance
  private static volatile Singleton m_instance;

  // Static synchronization root object, for locking
  private static object m_syncRoot = new object();

  // Property to retrieve the only instance of the Singleton
  public static Singleton Instance
   {
      get
      {
          // Check that the instance is null
          if (m_instance == null)
          {
              // Lock the object
              lock (m_syncRoot)
              {
                  // Check to make sure its null
                  if (m_instance == null)
                  {
                      m_instance = new Singleton();
                  }
              }
          }

          // Return the non-null instance of Singleton
          return m_instance;
      }
  }
} 
  1. 在哪种情况下,您会选择急切初始化还是延迟初始化?
  2. 第一个示例中的注释是否正确地说初始化是线程安全的? (我知道它说是,但它是互联网......)

【问题讨论】:

标签: c# design-patterns


【解决方案1】:

我肯定会选择你的第一个实现......

第二个对我来说似乎有问题...如果您需要/想要一个惰性实现,您可以为此使用Lazy<T> - 因为它是框架的一部分,所以感觉更舒服..

顺便说一句:还有更多方法可以实现单例模式...here is an excellent article

【讨论】:

  • 感谢您的链接,看到使用Lazy<T> 的实现很有趣:)
  • 你每天都会学到一些东西,我对所有关于单身人士的谈话感到非常无聊,但我不知道 Lazy。现在我期待着下一个关于单身人士的愚蠢面试问题。谢谢Yahia。
【解决方案2】:

我不确定,但您似乎从这里获得了这些示例:http://www.yoda.arachsys.com/csharp/singleton.html

如果没有,请通读它。关于这两个版本有一些想法。 如果您亲自问我:如果我需要知道单例是否已经初始化,我会选择第二种解决方案。

如果您不必处理多线程,我会使用更简单的方法(请参阅参考链接中的“错误代码”示例)。

【讨论】:

  • "。如果您亲自问我:如果我需要知道单例是否已经初始化,我会选择第二种解决方案。"阅读您的链接。第二个示例在此处被列为已损坏。
  • 这里可能存在误解:链接文档的第二版 = “第二版 - 简单线程安全”。但我同意,这没有明确说明。
  • 今天早上我读了很多关于各种设计模式的资料,因为我正在用我知道的所有语言实现它们,所以它可能来自那里。这只是我记下的两个。再次感谢您的链接:) 糟糕的代码是有原因的?你为什么推荐使用它?
  • 据我了解,“坏代码”是指它不是多线程安全的。如果只有一个线程,则需要使其比所需的更复杂。从这个意义上说,我会推荐更简单/最简单的解决方案。
【解决方案3】:

第一个既安全又懒惰。

static constructors 保证只执行一次,并且在第一次访问Instrance 之前立即执行。如果有一个静态构造函数(即使是空的),那么静态字段初始化保证在静态构造函数之前直接执行。如果没有静态构造函数,可能会提前进行字段初始化。


第二个是懒惰的,但是我不确定双锁模式是否像这样有效。我怀疑它坏了,至少在 ECMA 内存模型中。


我个人会避免任何Class.Instance 单例模式,而在大多数情况下支持 IoC 单例。

【讨论】:

  • 第一个懒惰的方式是什么? :s
  • 实例仅在第一次访问.Instance时被构造。
  • CodeInChaos 是正确的,直到我刚刚检查过,我还错误地认为静态是在类加载时初始化的。请原谅我是一个书呆子,但你的意思是.instance,没有.Instance。
【解决方案4】:

1) 这完全是一种设计选择。预先初始化或在需要时初始化。

2) 是的,它是线程安全的,因为 CLR 保证单线程对象初始化。 (静态和实例)

编辑

就个人而言,在第一个示例中,我公开了 Instance 字段并省去了 getter。有兴趣知道是否有任何理由认为这是一个坏主意?

【讨论】:

    【解决方案5】:

    这是一个单例,所以我会选择选项 1,除非它是一个甚至并不总是需要的巨大物体。但我可能不会为通常根本不使用的东西制作单例。

    【讨论】:

      【解决方案6】:

      两种实现都很好,所以这取决于你的需要。

      如果性能不是问题,请使用第一个急切创建的实例。否则,请使用第二个,其中仅同步第一个访问。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-27
        • 1970-01-01
        • 2017-07-01
        • 2013-11-22
        • 2014-06-02
        • 2018-06-12
        • 2011-09-19
        相关资源
        最近更新 更多