单例模式
Singleton单例:一个类在有且只有一个实例,并提供一个全局的访问点,私有化构造函数,提供一种机制来保证一个类只有一个实例。
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
四种实现方式:
- 简单模式
namespace 大话设计模式 { /// <summary> /// 简单实现单例 /// </summary> public sealed class SimpleSingleton { SimpleSingleton() { } public string Name { get; set; } private static SimpleSingleton singleton; public static SimpleSingleton Instance { get { if(singleton==null) { singleton=new SimpleSingleton(); } return singleton; } } public void GetStr() { Console.WriteLine(Name); } } }
优点:通过私有化构造函数,私有静态变量存储实例,通过静态属性访问实例,只有私有实例变量不为空时,才初始化对象。
缺点:无法保证线程安全。
- 安全线程
线程安全是在访问唯一实例时,将通过padlock来锁住唯一实例对象,这样就防止在多线程的情况下,创造出多个对象。
namespace 大话设计模式 { public sealed class ThreadSafeSingleton { private static readonly object padLock = new object(); private static ThreadSafeSingleton threadSafeSingleton; public string Name { get; set; } public int Index = 0; private ThreadSafeSingleton() { Name =Guid.NewGuid().ToString(); Thread.Sleep(2000); } public void Introduce() { Index++; Console.WriteLine(Thread.CurrentThread.Name+"——》key:"+Name); Console.ReadLine(); } public static ThreadSafeSingleton Instance() { if (threadSafeSingleton == null) { lock (padLock) { if (threadSafeSingleton == null) { threadSafeSingleton = new ThreadSafeSingleton(); } } } return threadSafeSingleton; } } }
线程安全分为两种:单锁和双重锁定,因为单例的特殊性,我们只需要保证是程序域中只有唯一的实例,因此我们只需要在实例为null的时候进行锁定,可以大大节省系统开销
我们通过多线程调用
-
namespace 大话设计模式 { class Program { static void Main(string[] args) { for (int i = 0; i < 10; i++) { Thread thread = new Thread(DoSomThing); thread.Name = "线程:" + i; thread.Start(); } Console.ReadLine(); } public static void DoSomThing() { var sigleton= ThreadSafeSingleton.Instance(); sigleton.Introduce(); } } }
有锁结果如图:
所有线程都是调用同一个对象
我们将锁注释掉以后调用结果如下
每个线程调用的对象不是同一个,因此违反了单例原则。
- 静态初始化
首先我们需要知道静态类的初始化顺序:静态字段,静态构造函数,静态方法的调用先后顺序
namespace 大话设计模式 { public static class SingletonStaic { private static string filedStatic = ExportStr("我是字段"); public static string ExportStr(string str) { Console.WriteLine(str); return str; } static SingletonStaic() { Console.WriteLine("我是构造函数"); } public static void MethodStaic1() { Console.WriteLine("我是方法一"); } public static void MethodStaic2() { Console.WriteLine("我是方法二"); } } }
调用
namespace 大话设计模式 { class Program { static void Main(string[] args) { SingletonStaic.MethodStaic1(); SingletonStaic.MethodStaic2(); Console.ReadLine(); } } }
因此调用先后顺序(静态字段——》静态构造函数——》静态方法)且静态字段和静态构造函数只调用一次
- 延迟加载
就是利用以上特性,利用内部类实现