设计模式2-单例(多线程)
单线程环境下的单例模型在多线程环境下最大的缺陷就是可能会出现多个线程同时调用GetInstance()方法,而可能会同时uniqueInstance==null而创建出多个实例,违背单一实例的初衷。
为了在多线程环境下也依然能够正确使用单例模式。就需要在判断时加锁。
public sealed class Singleton { //定义一个静态变量来保存类的实例 private static volatile Singleton uniqueInstance; //为lock定义一个object对象 private static readonly object locker = new object(); //定义私有构造函数,使外界不能创建类实例 private Singleton() { } /// <summary> /// 定义公有方法,提供一个全局访问点,同时也可以定义公有属性来提供全局访问点 /// </summary> /// <returns></returns> public static Singleton GetInstance() { //双重锁定 //1、每一个线程会先判断实例是否存在,如果不存在,才进行加锁 //2、如果直接加锁后再判断,会有额外的性能开销 //3、lock语句运行完毕后,才会对该对象解锁 if (uniqueInstance == null) { lock (locker) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } }
关于volatile关键字:被volatile修饰的对象表示该对象可能会被多个并行执行线程修改,声明为volatile的对象可以保证该对象自始至终都是最新的值。(每次读取这个值的时候,都会很小心的去读它最新的值)。
单例模式的优点:
1、实例控制:Singleton会阻止其他对象实例化其自己的Singleton对象的副本,从而确保所有对象都访问唯一实例
2、灵活性:类控制了实例化过程,所以类可以更加灵活修改实例化过程
单例模式的缺点:
1、开销:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,仍然会有定的开销,可以通过静态初始化解决。
2、开发混淆:因为不能使用new关键字实例化对象,所以可能无法访问源代码
3、生存期:因为包含有对该静态的私有字段的引用,而静态字段不会被CLR回收,所以该实例会和应用程序声明周期一样长,一直存在。
单例模式使用场景:
1、当类只能有一个实例且何苦可以从一个众所周知的访问点访问。
2、当这个唯一实例应该通过子类化扩展,且客户应该无需修改代码就能使用一个扩展的实例时。