Singleton几种单例模式
三板斧保证强制单例
1.构造函数私有化,避免重复构造
2.公开静态方法提供实例,这样外部才可以使用
3.静态变量共享,保证全局对象唯一
三板斧下来,就可以保证多次使用该对象,也一直是同一个实例!
public class Singleton { private Singleton()//构造函数私有化 { long iResult = 0; for (int i = 0; i < 100-000-000; i++) { iResult += i; } Thread.Sleep(2000); Console.WriteLine($"{this.GetType().Name} 完成构造..."); } private static Singleton singleton = null;//静态变量 public static Singleton CreateInstance()//公开的静态方法 { if (singleton == null) { singleton = new Singleton(); } return singleton; } public void Show() { Console.WriteLine($"{this.GetType().Name}Show。。。。"); }
}
看效果....
当然,这种形式的单例,只适用于单线程。如果是多线程就不能保证是一个对象只实例化一次
多线程?
很多程序在单线程下跑的很好。却经不起多线程的考验,然而多线程是无法避免的,那我们继续改进一下代码
接下来我们继续改造一下多线程的单例模式,使用的是lock锁,简单粗暴的就属它。
public class Singleton { private Singleton() { long iResult = 0; for (int i = 0; i < 100-000-000; i++) { iResult += i; } Thread.Sleep(2000); Console.WriteLine($"{this.GetType().Name} 完成构造..."); } private static Singleton singleton = null; private static readonly object singleton_Lock = new object(); public static Singleton CreateInstance() { if (singleton == null) { lock (singleton_Lock)//保证方法块只有一个线程可以进入 { Console.WriteLine("进入lock排队...."); Thread.Sleep(1000); if (singleton == null) { singleton = new Singleton(); } } } return singleton; } public void Show() { Console.WriteLine($"{this.GetType().Name}Show。。。。"); } }
调用看一下效果
这就到达了我们想要的效果。
当然还有更简便的方法,前面的属于懒汉模式,下面这两种称之为饿汉模式,我们往下看代码.....
public class SingletonSecond { private SingletonSecond() { long iResult = 0; for (int i = 0; i < 100-000-000; i++) { iResult += i; } Thread.Sleep(2000); Console.WriteLine($"{this.GetType().Name} 完成构造..."); } private static SingletonSecond Instance = null; /// <summary> /// 静态函数构造:由CRL调用,在类型第一次被调用前,且只调用一次 /// </summary> static SingletonSecond() { Instance = new SingletonSecond(); } public static SingletonSecond CreateInstance() { return Instance; } public void Show() { Console.WriteLine($"{this.GetType().Name}Show。。。。"); } public static void DoNothing() { Console.WriteLine("DoNothing"); } }
还有一种静态字段的单例模式,实现方式如下:
public class SingletonThird { private SingletonThird() { long iResult = 0; for (int i = 0; i < 100-000-000; i++) { iResult += i; } Thread.Sleep(2000); Console.WriteLine($"{this.GetType().Name} 完成构造..."); } private static SingletonThird Instance = new SingletonThird (); /// <summary> /// 静态字段:由CRL调用,在类型第一次被使用前初始化,且只调用一次 /// </summary> public static SingletonThird CreateInstance() { return Instance; } public void Show() { Console.WriteLine($"{this.GetType().Name}Show。。。。"); } public static void DoNothing() { Console.WriteLine("DoNothing"); } }
最后,对比一下单例模式和普通实例
看起来单例模式好像还不如普通实例,但是为啥又有单例模式呢?到底什么时候使用?
二者答案是一个,常规情况下,不推荐使用单例模式(项目使用IOC时,单例类都不需要自行实现了,直接可以用容器来完成单例)
只有在场景要求必须是单例的时候,我们才会去使用单例,比如:数据库连接池、线程池、IOC容器实例等等。一个进程只需一个实例,多个实例反而容易出现问题!!