单例模式
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们可以让一个全局变量使得一个对象被访问,但他不能防止你实例化多个对象。
一个最好的办法就是,让类自身负责保存他的唯一实例。
这个类可以保证没有其他实例可以被窗创建,并且他可以提供一个访问该实例的方法。
单例模式结构演示
class Singleton{ //静态单例成员变量 private static Singleton instance; //私有构造器,使其无法被外界创建实例 private Singleton() { } //静态方法,获取实例,第一次获取时创建实例 public static Singleton GetInstance(){ if (instance == null) instance = new Singleton(); return instance; } }
单例模式因为单例类封装他唯一的实例,这样他可以严格地控制客户怎样访问它以及何时访问它。即对唯一实例地受控访问。
多线程时的单例
lock是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。
如果其他线程试图进入锁定的代码,则他将一直等待,直到该对象被释放。
private static Singleton instance; private static readonly object syncRoot = new object(); private Singleton() { } public static Singleton GetInstance(){ lock(syncRoot){ if (instance == null) instance = new Singleton(); } return instance; }
之所以再使用一个syncRoot作为lock地参数,是一位加锁时不知道instance实例有没有被创建。
但是这样每次调用GetInstance方法时都要lock。
双重锁定
再加一层instance==null的判断,判断实例是否存在,不存在的情况再进行加锁处理。
public static Singleton GetInstance(){ if (instance == null){ lock (syncRoot){ if (instance == null) instance = new Singleton(); } } return instance; }
之所以内部还需要再判断一次是因为,假如实例还未创建,两个线程通过了第一层。
第一个线程先进入锁内,创建了实例,如果不加判断,第二个线程就又创建一次实例。
静态初始化
C#与公共语言运行库也提供了一种静态初始化的方法,这种方法不需要显式地编写线程安全代码,即可解决多线程环境下他是不安全的问题。
public sealed class Singleton{ private static readonly Singleton instance=new Singleton(); private Singleton() { } public static Singleton GetInstance() => instance; }
这种实现和前面的类似,也是解决了全局访问和实例化控制这两个问题,公共静态属性为访问实例提供了一个全局访问点。
不同的是,它依赖于公共语言运行库来初始化变量。由于构造器时私有的,不能在类本身以为实例化单例类,因此变量引用的是可以在系统中存在的唯一实例。
这种静态初始化的方法是在自己被加载时就将自己实例化,所以被称为饿汉式单例类。
之前的单例处理模式是要在第一次被引用时才会将自己实例化,被称为懒汉式单例类。