单例模式是一种创建型模式,它能确保一个类只有一个实例,并提供一个访问该实例的全局节点。
一个类的对象永远只会在当前进程中被创建一次,也就是说构造函数只可能被调用一次,不论有多少线程调用。为什么需要单例,假如这个类是用来操作某个资源的,如果存在多个这个类的实例,这可能在操作这个资源的时候造成破坏,所以只能创建一个实例是很有必要的。
所有单例的实现都包含以下两个相同的步骤:
new
运算符。如果你的代码能够访问单例类, 那它就能调用单例类的静态方法。 无论何时调用该方法, 它总是会返回相同的对象。
getInstance
获取实例的静态方法来返回其所属类的一个相同实例。
单例的构造函数必须对客户端(Client)代码隐藏。 调用获取实例方法必须是获取单例对象的唯一方式。一般来说,直接把对象声明为静态即可,程序集在加载过程中进行构造,这个也是线程安全的。但问题是如果此对象一直没有被调用,同时构造函数的开销较大,这个会造成资源浪费。
1234567891011121314151617 | class Singleton{ private static Singleton instance = new Singleton(); /// <summary> /// 构造函数声明为私有 /// </summary> private Singleton() { Console.WriteLine("执行构造函数"); } public static Singleton Get() { return instance; }} |
---|
著名的双检锁法,只在需要时执行构造函数,同时也是线程安全的
123456789101112131415161718192021222324252627282930313233 | class Singleton{ private static Singleton instance = null; private static readonly object lockobj = new object(); /// <summary> /// 构造函数声明为私有 /// </summary> private Singleton() { Console.WriteLine("执行构造函数"); } /// <summary> /// 双检锁 /// </summary> /// <param name="owner"></param> /// <returns></returns> public static Singleton Get() { if (instance == null) { lock (lockobj) { if (instance == null) { instance = new Singleton(); } } } return instance; }} |
---|
线程安全单例的完整代码示例:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 | using System;using System.Threading;namespace Singleton{ // This Singleton implementation is called "double check lock". It is safe // in multithreaded environment and provides lazy initialization for the // Singleton object. class Singleton { private Singleton() { } private static Singleton _instance; // We now have a lock object that will be used to synchronize threads // during first access to the Singleton. private static readonly object _lock = new object(); public static Singleton GetInstance(string value) { // This conditional is needed to prevent threads stumbling over the // lock once the instance is ready. if (_instance == null) { // Now, imagine that the program has just been launched. Since // there's no Singleton instance yet, multiple threads can // simultaneously pass the previous conditional and reach this // point almost at the same time. The first of them will acquire // lock and will proceed further, while the rest will wait here. lock (_lock) { // The first thread to acquire the lock, reaches this // conditional, goes inside and creates the Singleton // instance. Once it leaves the lock block, a thread that // might have been waiting for the lock release may then // enter this section. But since the Singleton field is // already initialized, the thread won't create a new // object. if (_instance == null) { _instance = new Singleton(); _instance.Value = value; } } } return _instance; } // We'll use this property to prove that our Singleton really works. public string Value { get; set; } } class Program { static void Main(string[] args) { // The client code. Console.WriteLine( "{0}\n{1}\n\n{2}\n", "If you see the same value, then singleton was reused (yay!)", "If you see different values, then 2 singletons were created (booo!!)", "RESULT:" ); Thread process1 = new Thread(() => { TestSingleton("FOO"); }); Thread process2 = new Thread(() => { TestSingleton("BAR"); }); process1.Start(); process2.Start(); process1.Join(); process2.Join(); } public static void TestSingleton(string value) { Singleton singleton = Singleton.GetInstance(value); Console.WriteLine(singleton.Value); } }} |
---|
执行结果:
12 | FOOFOO |
---|
参考原文:单例设计模式