一、简介
单例模式主要用的作用是用于保证程序运行中某个类只有一个实例,并提供一个全局入口点。单例模式(Singleton)为GOF阐述的标准24种设计模式中最简单的一个。但随着时间推移,GOF所阐述的单例实现已不能完全满足实际应用。
"ensure a class has only one instance, and provide a global point of access to it"
二、动机(应用场景)
几乎在每个应用程序中,都需要有一个从中进行全局访问和维护某种类型数据的区域。 在面向对象的 (OO) 系统中也有这种情况,在此类系统中,在任何给定时间只应运行一个类或某个类的一组预定义数量的实例。
1、当使用某个类来维护增量计数器时,此简单的计数器类需要跟踪在多个应用程序领域中使用的整数值。 此类需要能够增加该计数器并返回当前的值。 对于这种情况,所需的类行为应该仅使用一个类实例来维护该整数,而不是使用其它类实例来维护该整数。
2、每台计算机可以有若干个打印机,但只能有一个Printer Spooler,避免两个打印作业同时输出到打印机。
3、PC机中可能有几个串口,但只能有一个COM1口的实例。
4、系统中只能有一个窗口管理器。
5.NET Remoting中服务器激活对象中的Sigleton对象,确保所有的客户程序的请求都只有一个实例来处理。
6.应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
三、C#实现
1、单线程实现
单线程单例模式实现/** *单例模式的单线程实现。无法保证单线程模式下只产出唯一的一个实例。 */ Class Singleton { private static Singleton Instance; //将构造函数定义为private防止该类在外部被实例化 //如需有将此类定义可继承的,则可将private更改为protected private Singleton(){} public static Singleton GetInstance() { //当处于多线程环境时,可能存在多个线程在由于代码执行的顺序导致 //多个线程生成多个实例,而违背该模式的初衷 if(Instance==null) { Instance=new Singleton(); } return Instance; } }
可以说是一个标准的单例的代码。
优点:
- 由于实例是在 Instance 属性方法内部创建的,因此类可以使用附加功能(例如,对子类进行实例化),即使它可能引入不想要的依赖性。
- 直到对象要求产生一个实例才执行实例化;这种方法称为"懒实例化"。懒实例化避免了在应用程序启动时实例化不必要的 singleton。
缺点:
多线程环境下它是不安全的。如果执行过程的不同线程同时进入 Instance 属性方法,那么可能会创建多个 Singleton 对象实例。每个线程都会执行下列语句,并决定必须创建新的实例。
2、多线程实现
多线程单例模式实现class Singleton { //volatile关键字。 这应该告诉编译器不要对代码重新排序,并且放弃优化。确保只有在实例变量分配完成后才能访问实例变量。 //防止由于编译器优化导致代码控制失效. private static volatile Singleton instance; //使用 syncRoot 实例来进行锁定(而不是锁定类型本身),以避免发生死锁。 private static object syncRoot = new Object(); private Singleton() {} public static Singleton Instance { get { //双重检验锁定- Double-Check Locking // double-check locking 方法解决了线程并发问题,同时避免在每个 Instance 属性方法的调用中都出现独占锁定。 if (instance == null) { lock (syncRoot) { if (instance == null) instance = new Singleton(); } } return instance; } } }
优点:由于实例的产生由自己控制,可以对非默认构造函数进行扩展、传参等操作。
缺点:实现相对复杂
3、C#简洁版
由于 C# 与公共语言运行库也提供了一种"静态初始化"方法,这种方法不需要开发人员显式地编写线程安全代码,即可解决多线程创建等问题。
简洁实现1public sealed class Singleton { //变量标记为 readonly,这意味着只能在静态初始化期间(此处显示的示例)或在类构造函数中分配变量。 private static readonly Singleton instance = new Singleton(); private Singleton(){} public static Singleton Instance { get { return instance; } } }
更简洁的方式:
简洁实现1public sealed class Singleton { public static readonly Singleton Instance = new Singleton(); private Singleton(){} }
因为静态构造函数是属于类的,而不属于任何一个实例,所以这个构造函数只会被执行一次,而且是在创建此类的第一个实例或引用任何静态成员之前,由.NET自动调用。
1、由于静态构造函数由.NET调用,所以不需要public和private等访问修饰符。
2、在创建第一个类实例或任何静态成员被引用时,.NET将自动调用静态构造函数来初始化类。(我们无法调用,也不知道它何时被调用)
3、静态构造函数属于类,构造函数属于实例,他们并不冲突。静态构造函数只会运行一次。
缺点:由于在此解决方案中由 .NET Framework 负责执行初始化,无法在实例化之前使用非默认的构造函数或执行其他任务。在大多数情况下,静态初始化是在.NET 中实现 Singleton 的首选方法。
四、总结
单线程版、多线程版、简洁版有各自的应用,没有那种实现是最好的。
总结上述三种实现方法,以是否需要在创建单例实例时传参或执行其他任务分两类。即:
1、不需要执行其他任务
使用简洁版即可以保障在单线程、多线程都能安全使用的同时,代码量较少。
2、需要
一般情况下,均为单线程版。则使用单线程创建。若程序有多线程应用则应用使用双重检测的多线程实现。
参考文档:
http://msdn.microsoft.com/zh-cn/library/ff650316.aspx
第一式、单例模式-Singleton模式(创建型)