单例模式的好处:
单例模式的好处就是单例,就是全局唯一的一个实例,应对一些特殊情况,比如数据库连接池(内置了资源)全局唯一奥玛生成器,单例可以避免重复创建,但是也会常驻内存,除非真的有必要,否则不要用单例模式。
单例模式:
1、构造函数私有化,避免别人还去new
2、公开的静态方法提供对象实例
3、初始化一个静态字段用于返回,保证全局都是这一个。
/// <summary> /// 单例类:一个构造对象很耗时耗资源类型 /// 懒汉式单例模式 /// </summary> public class Singleton { /// <summary> /// 构造函数耗时耗资源 /// </summary> private Singleton() { } /// <summary> /// 3 全局唯一静态 重用这个变量 /// </summary> private static volatile Singleton _Singleton = null; /// <summary> /// 2 公开的静态方法提供对象实例 /// </summary> /// <returns></returns> public static Singleton CreateInstance() { _Singleton = new Singleton(); return _Singleton; } }
可以用以object.ReferenceEquals来验证创建的实例是不是同一个
Singleton singleton1 = Singleton.CreateInstance(); Singleton singleton2 = Singleton.CreateInstance(); Singleton singleton3 = Singleton.CreateInstance(); Console.WriteLine(object.ReferenceEquals(singleton1, singleton2)); Console.WriteLine(object.ReferenceEquals(singleton3, singleton2));
在多线程下,同事开启5个线程去创建呢?
for (int i = 0; i < 5; i++) { Task.Run(() =>//启动线程完成--5个线程并发执行,同时去执行这个方法 { Singleton singleton1 = Singleton.CreateInstance(); singleton1.Show(); }); }
这里就会出现多线程的问题,下面来解决多线程面临的问题。
/// <summary> /// 单例类:一个构造对象很耗时耗资源类型 /// 懒汉式单例模式 /// </summary> public class Singleton { /// <summary> /// 构造函数耗时耗资源 /// </summary> private Singleton() { long lResult = 0; for (int i = 0; i < 10000000; i++) { lResult += i; } Thread.Sleep(2000); Console.WriteLine("{0}被构造一次", this.GetType().Name); } /// <summary> /// 3 全局唯一静态 重用这个变量 /// </summary> private static volatile Singleton _Singleton = null; //volatile 促进线程安全 让线程按顺序操作 private static readonly object Singleton_Lock = new object(); /// <summary> /// 2 公开的静态方法提供对象实例 /// </summary> /// <returns></returns> public static Singleton CreateInstance() { if (_Singleton == null)//是_Singleton已经被初始化之后,就不要进入锁等待了 { lock (Singleton_Lock) //保证任意时刻只有一个线程进入lock范围 //也限制了并发,尤其是_Singleton已经被初始化之后 { //Thread.Sleep(1000); //Console.WriteLine("等待锁1s之后才继续。。。"); if (_Singleton == null)//保证只实例化一次 { _Singleton = new Singleton(); } } } return _Singleton; } //既然是单例,大家用的是同一个对象,用的是同一个方法,那还会并发吗 还有线程安全问题吗? public int iTotal = 0; public void Show() { //lock (Singleton_Lock) //{ this.iTotal++; //} } public static void Test() { Console.WriteLine("Test1"); Console.WriteLine(_Singleton.iTotal); } }