再谈Singleton

Singleton是开发模式中较为简单的模式。

定义:确保一个类只有一个实例,并提供一个全局访问点。

先看一个合法的定义:

public class MyClass
{
private MyClass(){    }
}
但是好像没有办法实例化。好了,看看实现吧

First version - not thread-safe

// Bad code! Do not use!
            public sealed class Singleton
            {
            static Singleton instance=null;
            private Singleton()
            {
            }
            public static Singleton Instance
            {
            get
            {
            if (instance==null)
            {
            instance = new Singleton();
            }
            return instance;
            }
            }
            }
看起来已经实现了Singleton,但是这种方式的缺点是"Not thread safe"(http://www.cnblogs.com/AllenYoung/archive/2006/04/14/375144.html)
 
Second version - simple thread-safety
public sealed class Singleton
            {
            static Singleton instance = null;
            static readonly object padlock = new object();
            private Singleton() { }
            public static Singleton Instance
            {
            get
            {
            lock (padlock)//vs: lock(typeof(Singleton))
            {
            if (instance == null)
            {
            instance = new Singleton();
            }
            return instance;
            }
            }
            }
            }
 

lock保证了一个时刻只能有一个线程进入该方法。缺点是每次实例化时同步带来了性能的降低,实际上只有第一次实例化才需要同步。

lock有两种方式,代码中采用的方式性能好一点。

 

Third version - attempted thread-safety using double-check locking

// Bad code! Do not use!
            public sealed class Singleton
            {
            static Singleton instance=null;
            static readonly object padlock = new object();
            Singleton()    {    }
            public static Singleton Instance
            {
            get
            {
            if (instance==null)
            {
            lock (padlock)
            {
            if (instance==null)
            {
            instance = new Singleton();
            }
            }
            }
            return instance;
            }
            }
            }
好了,把First version, Second version结合一下。
【原文bad code的原因
  • It doesn't work in Java. This may seem an odd thing to comment on, but it's worth knowing if you ever need the singleton pattern in Java, and C# programmers may well also be Java programmers. The Java memory model doesn't ensure that the constructor completes before the reference to the new object is assigned to instance. The Java memory model underwent a reworking for version 1.5, but double-check locking is still broken after this without a volatile variable (as in C#).
  • Without any memory barriers, it's broken in the ECMA CLI specification too. It's possible that under the .NET 2.0 memory model (which is stronger than the ECMA spec) it's safe, but I'd rather not rely on those stronger semantics, especially if there's any doubt as to the safety. Making the instance variable volatile can make it work, as would explicit memory barrier calls, although in the latter case even experts can't agree exactly which barriers are required. I tend to try to avoid situations where experts don't agree what's right and what's wrong!
  • It's easy to get wrong. The pattern needs to be pretty much exactly as above - any significant changes are likely to impact either performance or correctness.
  • It still doesn't perform as well as the later implementations.】

    我认为增加一个volatile关键字就可以了,没有搞懂原文的意思到底行还是不行:static volatile Singleton instance=null; 这也是HeadFirst中的最终版本。

     
    Fourth version - not quite as lazy, but thread-safe without using locks(急切实例化)
     
    public sealed class Singleton
                {
                static readonly Singleton instance=new Singleton();
                // Explicit static constructor to tell C# compiler 
                // not to mark type as beforefieldinit 
                static Singleton() {  }
                Singleton() { }
                public static Singleton Instance
                {
                get
                {
                return instance;
                }
                }
                }
    这种作法的缺点是类被加载时intrance就被实例化了,会增加运行负载。(看到网上有人说这是C#相对于java特有的方式,这种说法是错误的)
     
    Fifth version - fully lazy instantiation
     
    public sealed class Singleton
                {
                Singleton() {}
                public static Singleton Instance
                {
                get
                {
                return Nested.instance;
                }
                }
                class Nested
                {
                // Explicit static constructor to tell C# compiler
                // not to mark type as beforefieldinit
                static Nested()
                {
                }
                internal static readonly Singleton instance = new Singleton();
                }
                }
    -----------------------------------------------------------------------------

    Code from: http://www.yoda.arachsys.com/csharp/singleton.html

    Reference:《HeadFirst设计模式》

     

     

  • posted @ 2008-05-10 21:46  KymoWang  阅读(528)  评论(1编辑  收藏  举报