设计模式——单例模式的实现[备忘录]
单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点。
“通常我们可以让一个全局变量使得一个对象被访问,但他不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存他的唯一实例。这个类可以保证没有其他实例可以被创建,并且他可以提供一个访问该实例的方法”。
结构图:
先创建一个简单的实例说明一下单例模式:
Singleton类:
/* * 单例模式的实现 */ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Singleton { public class Singleton { private static Singleton instance; //定义其构造方法为private,防止外界利用new创建此类实例的可能。 private Singleton() { } //通过此方法获得本类实例的唯一全局访问点。 public static Singleton Instance() { if (instance==null )//若实例不存在,则new一个新实例,否则返回已有的实例; { instance = new Singleton(); } return instance; } } }
客户端调用:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Singleton { class Program { static void Main(string[] args) { Singleton s1 = Singleton.Instance(); Singleton s2 = Singleton.Instance(); if (s1==s2) { Console.WriteLine("两个对象是相同的实例。"); } Console.ReadLine(); } } }
单例模式的初衷是为了保证一个类仅有一个实例。而在多线程就不能保证一个类在多个线程访问下,拥有一个实例。那么我们在多线程的环境下,怎么实现单例模式呢?
Singleton类:
/* * 单例模式的实现 */ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Singleton { /// <summary> /// 安全线程的实现 /// </summary> public sealed class Singleton { private static Singleton instance = null; //程序运行时创建一个静态只读的进程辅助对象 private static readonly object padlock = new object(); private Singleton() { } public static Singleton Instance() { lock (padlock) //在同一个时刻加了锁的那部分程序只有一个进程可以进入。 { if (instance == null) { instance = new Singleton(); } return instance; } } } }
创建padlock对象的目的:在进程加锁时,instance实例有没有创建并不知道,无法加锁。
但是每次调用Instance时,总需要lock,会影响性能,接下来我们做一下改良。
双重锁定:
/* * 单例模式的实现 */ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Singleton { /// <summary> /// 安全线程的实现 /// </summary> public sealed class Singleton { private static Singleton instance = null; //程序运行时创建一个静态只读的进程辅助对象 private static readonly object padlock = new object(); private Singleton() { } public static Singleton Instance() { if (instance==null) { lock (padlock) //在同一个时刻加了锁的那部分程序只有一个进程可以进入。 { if (instance == null) { instance = new Singleton(); } } } return instance; } } }
双重锁定是解决当instance为null时,同时有两个线程调用Instance()方法时,它们都可以通过instance==null的判断,然后只有一个线程进入,另一个在外排队等候,如果没有第二层instance=null的判断,第一个线程创建了实例,而第二个线程在等待创建实例,违背了单例模式的初衷。
以上代码同时也展示了静态初始化。
instance变量标记为readonly,只能是在静态初始化期间或者在类构造函数中分配变量。
这种静态初始化的方式是在自己被加载是就将自己实例化------恶汉式单例类。
要是在第一次被引用是,才会将自己实例化------------------懒汉式单例类。
本文版权归本人和博客园共同所用,转载请注明出处。