参考:
- 《Implementing the Singleton Pattern in C#》
- 《CLR via C# (第4版)》
方式1. 非线程安全
public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton GetInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
可能有两个线程都执行了 'if (instance==null)',且得到的结果都是 true,然后两个线程各自创建一个实例。
(有可能在执行 'if (instance==null)' 前,实例就已经创建好了,但是 memory model 不能保证其它线程能及时发现 instance 的值已经改变。(内存栅栏,memory barrier))
方式2. 简单的线程安全
public sealed class Singleton { private static readonly object s_lock = new object(); private static Singleton instance = null; private Singleton() { } public static Singleton GetInstance() { lock (s_lock) { if (instance == null) { instance = new Singleton(); } return instance; } } }
lock 可以消除内存栅栏的影响。
在CLR 中,任何锁方法的调用都构成了一个完整的内存栅栏,在栅栏之前写入的任何变量都必须在栅栏之前完成;在栅栏之后的任何变量读取都必须在栅栏之后开始。
缺点:每次获取 instance 都得拿锁,性能会降低。
方式3. 用双检锁实现线程安全
public class Singleton { private static object s_lock = new object(); private static Singleton instance = null; private Singleton() { } public Singleton GetInstance() { if (instance == null) { Monitor.Enter(s_lock); if (instance == null) { Singleton temp = new Singleton(); Volatile.Write(ref instance, temp); } } return instance; } }
> 为什么用 Volatile.Write 而不是 instance = new Singleton() ?
如果用 instance = new Singleton(),编译器可能先为 Singleton 分配内存,将引用赋给 instance,再调用构造器。这样可能在调用构造器完成之前,另一个线程调用了 GetInstance 并使用这个未构造完成的 Singleton 对象。
Volatile.Write 保证 temp 中的引用只有在构造器结束后才赋给 instance。
方式4. 不用锁的线程安全、非延迟创建
public class Singleton { private static readonly Singleton instance = new Singleton(); private Singleton() { } public static Singleton GetInstance() { return instance; } }
缺点:首次访问类的任何成员都会调用类型构造器,从而创建实例。
方式5. 延迟创建
public class Singleton { private Singleton() { } public static Singleton GetInstance() { return Nested.instance; } private class Nested { internal static readonly Singleton instance = new Singleton(); } }
方式6. 用 Lazy<T>
public class Singleton { private static Lazy<Singleton> instance = new Lazy<Singleton>(() => new Singleton(), true); private Singleton() { } public Singleton GetInstance() { return instance; } }
小结:
不要炫技!
延迟创建实例确实可以加快类的加载速度,但这只是转移了耗时的阶段。是快速启动更重要,还是后续快速获取实例更重要,这得看具体业务需求。而且实现延迟创建的代码一般都更复杂。
一般我用这种方式:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton GetInstance() { return instance; } }
如果需要延迟创建就用方式6。
相关推荐
C#单例模式C#单例模式详解C#单例模式详解C#单例模式详解
C# 单例模式小实例C# 单例模式小实例C# 单例模式小实例C# 单例模式小实例C# 单例模式小实例
一个用C#写的 实现单例模式的源码程序和大家分享交流一下
c#单例模式示例,帮助实现懒惰加载,线程安全。
C#版本的单例模式源码
C#单例模式的应用,这里给的是C#里面一个单例模式的应用案例,面向对象过程中不可避免的需要用到单例模式,我在博客园中有详细说明单例模式怎么应用的,链接地址:...
以前学校让做的项目,留给初学者参考,里面使用单例模式设计的,对初学者有很大的帮助,简单易懂。很好的资源
1.1.1 摘要 ...单例模式(Singleton)是几个创建模式中最对立的一个,它的主要特点不是根据用户程序调用生成一个新的实例,而是控制某个类型的实例唯一性,通过上图我们知道它包含的角色只有一个,
如题。 没有什么特别要说明的。 一个C#版单例模式的xml解析类
C#单例模式的讲解视频,内容很好是学习编程模式的好资料。
主要介绍了c# 单例模式的实现方法,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
帮助你充分理解单例模式,非常好理解的模型,下载下来试试看吧,不需要积分。
本压缩包含有两个demo,分别对应<设计模式>第2版,刘伟这本书,单例模式这一章课后习题6、7,如果问题请留言一起探讨,谢谢!
主要介绍了C#单例模式(Singleton Pattern)的实现方法,主要讲述了即时加载的单例模式、延迟加载的单例模式与线程安全的单例模式,需要的朋友可以参考下
主要为大家详细介绍了C#单例模式Singleton Pattern的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
单例模式窗口的实现,c#程序,winform,实现单例窗口,点击后不会新弹出页面
C# 实例 源码 利用vs2005创建源码 北大青鸟ACCP 合肥科海-浪漫的明明 谢谢分享