设计模式——单例模式
一、单例模式:保证进程中,类型只有一个实例
a) 构造函数私有化,防止他人实例化
b) 对外提供一个获取实例的途径,公开的静态方法
c) 返回共用一个静态字段
二、为什么使用单例
并不一定节省资源, 因为对象常驻内存,没有及时释放。
速度会快一点,重用对象,如果每次new新对象--使用--释放,耗时。
应用场景:
线程池 流水号生成器 配置文件读取 IOC容器实例
数据库连接池:数据库连接--非托管资源--申请/释放消耗性能
池化资源--内置10个链接---使用来拿,用完放回来--避免重复申请和销毁--控制链接数量
注意事项:单例并不能用来解决多线程并发问题。比如单例类里有一个整形字段number,如果多线程实例化这个类1000次,每次对这个字段进行++操作,即使这1000次实例化出来的对象都是同一个,但最后的结果一定是小于1000的,因为多线程对同一个资源操作,会线程冲突、线程不安全。
三、单线程写法
public class Singleton { /// <summary> /// 私有构造函数 /// </summary> private Singleton() { Console.WriteLine($"{this.GetType().Name}被构造一次"); } private static Singleton _Singleton = null; public static Singleton CreateInstance() { if (_Singleton == null) { _Singleton = new Singleton(); } return _Singleton; } }
四、多线程写法
1、单锁(懒汉式)
1 public class Singleton 2 { 3 /// <summary> 4 /// 私有构造函数 5 /// </summary> 6 private Singleton() 7 { 8 Console.WriteLine($"{this.GetType().Name}被构造一次"); 9 } 10 11 private static Singleton _Singleton = null; 12 private static readonly object Singleton_Lock = new object(); 13 public static Singleton CreateInstance() 14 { 15 //开始多线程初始化---lock锁定--线程请求锁--开始判断创建 16 17 lock (Singleton_Lock)//可以保证任意时刻只有一个线程进入,其他线程等待 18 { 19 if (_Singleton == null)//这个判断不能去掉,保证只初始化一次 20 { 21 _Singleton = new Singleton(); 22 } 23 } 24 25 return _Singleton; 26 } 27 }
流程:开始多线程初始化---lock锁定--线程请求锁--开始判断创建
缺点:如果以上多线程都结束后---再来多个线程请求呢?--都需要等待锁--拿到锁--进去判断--不为空--返回对象--。。。。
这样很浪费,因为此时对象已经创建了,不需要等待锁,直接判断就行了
所以有了以下双检锁方法
2、双检锁(懒汉式)
public class Singleton { /// <summary> /// 私有构造函数 /// </summary> private Singleton() { Console.WriteLine($"{this.GetType().Name}被构造一次"); } private static Singleton _Singleton = null; private static readonly object Singleton_Lock = new object(); public static Singleton CreateInstance() { //开始多线程初始化---lock锁定--线程请求锁--开始判断创建 if (_Singleton == null) { lock (Singleton_Lock)//可以保证任意时刻只有一个线程进入,其他线程等待 { if (_Singleton == null)//这个判断不能去掉,保证只初始化一次 { _Singleton = new Singleton(); } } } return _Singleton; } }
以上两种方法因为都只有在调用CreateInstance方法时才实例化,所以称为懒汉式(饿的时候才吃)。
3、静态字段(饿汉式)
public class Singleton { /// <summary> /// 私有构造函数 /// </summary> private Singleton() { Console.WriteLine($"{this.GetType().Name}被构造一次"); } /// <summary> /// 静态字段:由CLR保障,在第一次使用这个类型之前,会自动初始化且只初始化一次 /// </summary> private static Singleton _Singleton = new Singleton(); public static Singleton CreateInstance() { return _Singleton; } }
静态字段:由CLR保障,在第一次使用这个类型之前,会自动初始化且只初始化一次