1.什么是单例模式
保证一个类最多只有一个实例(实例化控制),并且提供一个访问它的全局访问点(全局访问)。
2.什么时候用
当创建一个对象比较耗费资源,而这个对象的实例只要有一个就可以使用,这个时候可以用到单例模式。
单例模式解决了,如何实现一个类只能被创建一次的问题。
3.代码示例
using System; namespace mydotnet { class Program { static void Main(string[] args) { Singleton singleton = Singleton.GetInstance();//客户端获取实例 } } public sealed class Singleton { private Singleton(){}//私有化构造函数,防止外部实例化,内部可以使用 private static Singleton instance;//必须是静态的,静态方法才能调用 public static Singleton GetInstance(){//公用静态方法,外部可以调用 if(instance == null) { instance = new Singleton(); } return instance; } } }
4.并发问题解决
上述代码是懒汉模式,第一次使用才会创建。发生并发时,可能会多次创建,解决并发可以考虑加lock。代码如下:
using System; namespace mydotnet { class Program { static void Main(string[] args) { Singleton singleton = Singleton.GetInstance();//客户端获取实例 } } public sealed class Singleton { private Singleton(){}//私有化构造函数,防止外部实例化,内部可以使用 private static Singleton instance;//必须是静态的,静态方法才能调用 private static readonly object syncLock = new object();//不直接锁定 instance是因为instance不一定已经创建了,lock的内容需要非空的引用类型 public static Singleton GetInstance(){//公用静态方法,外部可以调用 lock(syncLock) { if(instance == null) { instance = new Singleton(); } return instance; } } } }
lock的作用是锁定某一代码块,让同一时间只有一个线程访问该代码块,详细参考:https://www.cnblogs.com/liuqiyun/p/9118382.html
5.双重锁定
public static Singleton GetInstance(){//公用静态方法,外部可以调用 if(instance == null)//避免没必要的lock资源浪费 { lock(instance) { if(instance == null)//不能去掉,如果同时进入lock还是可以重复创建 { instance = new Singleton(); } return instance; } } }
6.饿汉模式
程序初始化时,就创建实例,不管用不用到。
饿汉模式,不要显式编写线程安全代码,就可以解决多线程环境下是否安全的问题。
解决方式使用静态初始化,代码如下:
using System; namespace mydotnet { class Program { static void Main(string[] args) { Singleton singleton = Singleton.GetInstance();//客户端获取实例 } } public class Singleton { private Singleton(){}//私有化构造函数,防止外部实例化,内部可以使用 private readonly static Singleton instance = new Singleton();//静态初始化,不需要显式的线程安全代码
//readonly,只能在静态初始化期间或在类的构造函数中修改,不写也没事,防止在其他方法中修改 public static Singleton GetInstance(){ return instance; } } }
也可以不写GetInstance方法,直接把instance设置为public,客户端直接写Singleton.instance实现更简单。
using System; namespace mydotnet { class Program { static void Main(string[] args) { Singleton singleton = Singleton.instance;//客户端获取实例 } } public class Singleton { private Singleton(){}//私有化构造函数,防止外部实例化,内部可以使用 public readonly static Singleton instance = new Singleton(); } }