单例模式主要解决的是,一个全局使用的类频繁的创建和消费,从而提升整体代码的性能。
在我们平时使用中,要确保一个类只能有一个实例对象,即使多线程同时访问,也只能创建一个实例对象,并需要提供一个全局访问此实例的点。
用来创建独一无二的,只能有一个实例对象的入场卷。
单例模式允许在程序的任何地方访问特定对象,但是它可以保护该实例不被其他代码覆盖。
使用场景:
代码结构:
实现方式:
优点:
缺点:
单例可以分很多实现方式,但是从大类上来划分,主要为懒汉模式和饿汉模式
/// <summary> /// 单例模式 (常规用法,线程不安全。) /// </summary> public class Singleton { /// <summary> /// 私有构造函数 /// </summary> private Singleton() { } /// <summary> /// 静态局部变量 /// </summary> private static Singleton _instance=null; /// <summary> /// 静态的全局唯一访问口 /// 只能得到缓存的静态局部变量实例,无法重新新建。 /// </summary> /// <returns></returns> public static Singleton GetInstance() { if (_instance==null) { _instance = new Singleton(); } return _instance; } }
此方法满足了懒加载,但是如果多个访问者同时进行访问获取对象,就会出现多个实例对象,就不是单例模式了,所以此方法在多线程场景是不实用的。
/// <summary> /// 单例模式 (常规用法,线程安全。) /// </summary> public class Singleton { /// <summary> /// 私有构造函数 /// </summary> private Singleton() { } /// <summary> /// 静态局部变量 /// </summary> private static Singleton _instance=null; /// <summary> /// 声明锁 锁同步 /// </summary> private static readonly object _lock = new object(); /// <summary> /// 静态的全局唯一访问口 /// 只能得到缓存的静态局部变量实例,无法重新新建。 /// </summary> /// <returns></returns> public static Singleton GetInstance(string value) { if (_instance == null) //双重判空,确保在多线程状态下只创建一个实例对象 { lock (_lock) //加锁,确保其每次只能由一个对象进行访问 { if (_instance==null) { _instance = new Singleton(); _instance.Value = value; } } } return _instance; } public string Value { get; set; } }
class Program { static void Main(string[] args) { Console.WriteLine("多线程进行访问"); Thread processOne = new Thread(() => { TestSingleton("阿辉"); }); Thread processTwo = new Thread(() => { TestSingleton("阿七"); }); processOne.Start(); processTwo.Start(); processOne.Join(); processTwo.Join(); Console.ReadKey(); } static void TestSingleton(string value) { Singleton s = Singleton.GetInstance(value); Console.WriteLine(s.Value); } }
可以看到在我们模拟的多线程访问过程中,即使设置的阿辉和阿七,最后输出的也只有阿辉,也就是说只能创建一个实例对象。
可以看到懒加载就是程序刚开始不实例化,只有在被调用或者需要使用它的时候才进行实例化操作,这就是懒加载。
public class Singleton1 { /// <summary> /// 饿汉式,也就是在程序运行时都已经进行了初始化操作,后续只是调用而已。 /// </summary> private static Singleton1 instance = new Singleton1(); private Singleton1() { } public static Singleton1 GetInstance() { return instance; } }
饿汉式顾名思义就是提前都恶的不行了,在程序刚开始启动的时候就已经将其进行了实例化,后续只管调用。
这种不是懒加载,无论程序是否会用到这个类,它都会提早的进行实例化。
public class Singleton2 { private static Singleton2 _Singleton2 = null; static Singleton2() { _Singleton2 = new Singleton2(); } public static Singleton2 CreateInstance() { return _Singleton2; } }
单例模式常用的就大体介绍完了,我们在平时的使用过程中需要根据不同的业务逻辑来选择不同的实现方式,不能说哪一种最好,也不能说哪一种不好,只是它们使用的场景不同而已。
人生短暂,我不想去追求自己看不见的,我只想抓住我能看的见的。
我是阿辉,感谢您的阅读,如果对你有帮助,麻烦点赞、转发 谢谢。