前言
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
Singleton类,定义一个GetInstance操作,允许客户访问它的唯一实例。GetInstance是一个静态方法,主要负责创建自己的唯一实例。
class Singleton { private static Singleton instance; //构造方法让其private,这就堵死了外界利用new创建此类实例的可能 private Singleton() { } //此方法是获得本类实例的唯一全局访问点 public static Singleton GetInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
客户端代码
static void Main(string[] args) { Singleton s1 = Singleton.GetInstance(); Singleton s2 = Singleton.GetInstance(); if (s1 == s2)//比较两次实例化后对象的结果是实例相同 { Console.WriteLine("两个对象是相同的实例"); } Console.Read(); }
多线程时的单例
class Singleton { private static Singleton instance; //程序运行时创建一个只读的进程辅助对象 private static readonly object syncRoot = new object(); //构造方法让其private,这就堵死了外界利用new创建此类实例的可能 private Singleton() { } //此方法是获得本类实例的唯一全局访问点 public static Singleton GetInstance() { lock (syncRoot) { if (instance == null) { instance = new Singleton(); } } return instance; } }
lock是锁的意思,再同一时刻加了锁的那一部分,只有一个线程可以进入。
但是这样做并不是最好的,程序每次进来都会lock,会比较影响性能,所以我们可以使用双重锁定。
class Singleton { private static Singleton instance; //程序运行时创建一个只读的进程辅助对象 private static readonly object syncRoot = new object(); //构造方法让其private,这就堵死了外界利用new创建此类实例的可能 private Singleton() { } //此方法是获得本类实例的唯一全局访问点 public static Singleton GetInstance() { //先判断实例是否存在,存在直接返回,不存在再进入锁 if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
再lock外层增加了一个实例是否存在的判断,看起来程序多用了一个无用判断,其实不然,最外层判断是判断实例是否存在,如果不存在,就加锁创建,如果没有里面一层判断,那当多线程使用时,可能同时两个线程越过第一重判断,进而多次实例化,这并不是我们想要的结果。所以,解决多线程单例的推荐方式是双重锁