【设计模式】————单例模式

来源:互联网 发布:i代表什么矩阵 编辑:程序博客网 时间:2024/05/18 20:07

          单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。让类自身负责保存它的唯一实例,这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

          类图:

         

懒汉式单例:

       

 class Singleton {     private static Singleton instance;      private Singleton()   //构造方法让其Private,这就堵死了外界利用new创建此类实例的可能     {     }     public static Singleton GetInstance    //此方法是获得本类实例的唯一全局访问点     {           if (instance==null)   //若实例不存在,则new一个新实例,否则返回已有的实例            {               instance = new Singleton();            }          return instance;      } }


优点:第一次调用才初始化,避免内存浪费

缺点:线程不安全,在多线程的程序中,多个线程同时,注意是同时访问Singleton类,调用GetInstance()方法,会有可能造成创建多个实例的。


安全的线程

  class Singleton {    private static Singleton instancel;    private static readonly object padlock = new object();  //程序运行时创建一个静态只读的进程辅助对象    Singleton()    {    }    public static Singleton Instance    {            lock (padlock)  //在同一时刻加了锁的那部分程序只有一个线程可以进入            {               if (instance==null)                {                    instance = new Singleton();                }               return instance;            }     }}

       Lock是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

     该种方式的实现对于线程来说是安全的。我们首先创建了一个进程辅助对象,线程在进入时先对扶助对象加锁后再检测对象是否被创建,这样可以确保只有一个实例被创建,因为在同一个时刻加了锁的那部分程序只有一个线程可以进入,这种情况下,对象实例由最先进入的那个线程创建,后来的线程在进入时(instence==null)为假,不会再去创建对象实例了,但这种实现方式增加了额外的开销,损失了性能。


双重检查锁定(Double-Check Locking)

class Singleton{    private static Singleton instance;    private static readonly object syncRoot = new object();    private Singleton(){};        public static Singleton GetInstance()    {       if(instance==null)   //先判断实例是否存在,不存在再加锁处理       {           lock(syncRoot)            {                if(instance==null)                 {                    instance=new Singleton();                              }            }       }        return instance;    }}

这种实现方式对多线程来说是安全的,同时线程不是每次都加锁,只有判断对象实例没有被创建时它才加锁,有了我们上面第一部分的里面的分析,我们知道,加锁后还得再进行对象是否已被创建的判断。它解决了线程并发问题,同时避免在每个 Instance 属性方法的调用中都出现独占锁定。它还允许您将实例化延迟到第一次访问对象时发生。实际上,应用程序很少需要这种类型的实现。大多数情况下我们会用静态初始化。这种方式仍然有很多缺点:无法实现延迟初始化。


饿汉式单例:

public class Singleton {    private static final Singleton instance= new Singleton();  //在第一次引用类的任何成员对创建实例。CLR负责处理变量初始化    private Singleton() {}    //此类不能被实例化    public static Singleton getInstance() {        return instance;    }}

饿汉式单例模式是指这种方式是在自己被加载时就将自己实例化,这样的话就提前占用了资源,多线程也不会产生影响。


静态内部类:

public sealed class Singleton {     //阻止发生派生,而派生可能会增加实例    private static readonly Singleton instance = new Singleton();      private Singleton (){}      public static Singleton GetInstance()      {         return instance;       }  } 

C#与公共语言运行库提供了一种"静态初始化"方法,这种方法不需要开发人员显式地编写线程安全代码,即可解决多线程环境下它是不安全的问题。在大多数情况下,静态初始化是在.NET中实现Singleton的首选方法。


总结:通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

2 0
原创粉丝点击