单例模式
摘要
在我们日常的工作中经常需要在应用程序中保持一个唯一的实例,如:IO处理,数据库操作等,由于这些对象都要占用重要的系统资源,所以我们必须限制这些实例的创建或始终使用一个公用的实例,这就是我们今天要介绍的——单例模式(Singleton)。
定义
单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点
结构图
结构图分析
包含角色:Singleton(唯一)
私有构造函数:确保用户无法通过new来直接实例它
静态私有成员变量instance:用于存放实例化的对象
Instance():检验并实例化自己,然后存放在静态成员变量中,确保实例的唯一性
几种常见的单例模式
1.线程不安全
2.线程安全
3.Double-Checked Locking
4.静态初始化
5.延迟初始化
6.Net4’s Lazy<T> type
线程不安全版

1 public sealed class SimpleSingleton : BaseSingleton 2 { 3 private static SimpleSingleton _instance = null; 4 private SimpleSingleton() { } 5 public static SimpleSingleton Instance 6 { 7 get 8 { 9 return _instance ?? (_instance = new SimpleSingleton()); 10 } 11 } 12 }
单线程环境,因为在多线程的环境下有可能得到Singleton类的多个实例。假如同时有两个线程去判断(null == _singleton),并且得到的结果为真,那么两个线程都会创建类Singleton的实例,这样就违背了Singleton模式“唯一实例”的初衷。使用条件:
改进方案:线程安全模式,支持多线程
线程安全

1 public class ThreadSafeSingleton : BaseSingleton 2 { 3 private static ThreadSafeSingleton _instance = null; 4 private static readonly object SynObject = new object(); 5 private ThreadSafeSingleton() { } 6 public static ThreadSafeSingleton Instance { 7 get { 8 lock (SynObject) {return _instance ?? (_instance = new ThreadSafeSingleton());} 9 } 10 } 11 }
首先我们创建了一个静态只读的进程辅助对象SynObject,由于lock是确保当一个线程位于代码的临界区时,另一个线程不能进入临界区(同步操作)。分析:
如果其他线程试图进入锁定的代码,则它将一直等待,直到该对象被释放。从而确保在多线程下不会创建多个对象实例了。
缺点:这种实现方式要进行同步操作,影响系统性能的瓶颈和增加了额外的开销。
改进方案:经典的Double-Checked Locking,降低同步操作的次数
Double-Checked Locking

1 public sealed class DoubleCheckedLockingSingleton : BaseSingleton 2 { 3 private static DoubleCheckedLockingSingleton _instance = null; 4 private static readonly object SyObject = new object(); 5 private DoubleCheckedLockingSingleton() { } 6 public static DoubleCheckedLockingSingleton Instance { 7 get { 8 if (null != _instance) { return _instance; } 9 lock (SyObject) {return _instance ?? (_instance = new DoubleCheckedLockingSingleton());} 10 } 11 } 12 }
这种模式支持了多线程的环境,也降低了同步操作的次数,降低了系统的开销。这就是经典的Double-CheckedLocking方法。分析
下面,讨论其他其中单例模式的实现方案。
其中涉及到的一个新的概念beforefieldinit,意思大概就是:该字段初始化可以发生在任何时候任何字段被引用之前。这里就不做过多介绍,暂且跳过。
静态初始化

1 public sealed class ThreadSafeNoLockSingleton : BaseSingleton 2 { 3 private static readonly ThreadSafeNoLockSingleton _instance = new ThreadSafeNoLockSingleton(); 4 static ThreadSafeNoLockSingleton() { } 5 private ThreadSafeNoLockSingleton() { } 6 public static ThreadSafeNoLockSingleton Instance 7 { 8 get { return _instance; } 9 } 10 }
优点:较之前的实现方式更为简单,且支持多线程环境分析
由于这种静态初始化的方式是在自己的字段被引用时才会实例化。因此即便很多线程试图引用_instance,也需要等静态构造函数执行完并把静态成员_instance实例化之后可以使用。单例的实现由C#语言本身的特性来。
延迟初始化

1 public sealed class LazySingleton : BaseSingleton 2 { 3 private LazySingleton() { } 4 public static LazySingleton Instance { get { return Nested._instance; } } 5 6 private class Nested 7 { 8 static Nested() { } 9 internal static readonly LazySingleton _instance = new LazySingleton(); 10 } 11 }
这种方案把初始化工作放到内部类Nested类中的一个静态成员来完成,以这种方式实现了延迟初始化分析
Lazy<T> type

1 public sealed class DotNetLazySingleton : BaseSingleton 2 { 3 private static readonly Lazy<DotNetLazySingleton> lazy = new Lazy<DotNetLazySingleton>(() => new DotNetLazySingleton()); 4 private DotNetLazySingleton() { } 5 public static DotNetLazySingleton Instance { get { return lazy.Value; } } 6 }
这种方式简单、性能良好,而且还提供检查是否已经创建实例的属性IsValueCreated.这是.Net4提供的一种解决方案分析
演示:
源代码:https://git.oschina.net/xrainchen/FrameworkDemo.git 分支:1.15.11.22.1
总结
单例模式(Singleton)会控制其实例对象的数量,从而确保访问对象的唯一性。
实例控制:单例模式防止其它对象对自己的实例化,确保所有的对象都访问一个实例。
伸缩性:因为由类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
参考:http://csharpindepth.com/Articles/General/Singleton.aspx
李宏:
单例最典型例子,就是反转依赖IOC里面最常用到的,单例最大好处在于他只有一个实例,每一次实例化都要有一次开销,如果某个方法常调用,那么他就有成千上万次实例化,开销是很大的
单例最大缺点,他因为只有一个实例,在高并发的情况下,如果有共享资源,导致线程不安全,锁这种办法是会影响性能
根据李宏的点评,我找了一篇文章:http://www.cnblogs.com/atwanli/articles/4740184.html