设计模式 -- 单例模式(单线程)
单例模式算是设计模式里最简单的一个设计模式了,讨论学习它,我们不用研究设计原则。它就是一个简单的类结构,来看看吧。
1、什么是单例模式?
单例模式确保一个类只有一个实例,并且提供一个全局的访问点。
也许你觉得一个类只能有一个实例简直就是浪费,可是有些情况,我们需要的就是只有一个实例的类,比如说线程池(threadpool),缓存(cache),对话框,处理偏好设置和注册表的对象,日志对象,充当打印机、显卡等设备的驱动器等。事实上,这些类对象只能有一个,如果实例化多个出来,就会导致许多问题产生,如:程序的行为异常,资源的使用过量,或者导致不一致的结果。
2、单例模式如何实现?
我说了,单例模式是设计模式里最简单的,通常我们实例化一个对象都是new,new也就意味着类要有一个公有的构造器,但是一旦构造器公有,那么我们实例化时就不会受限制了,为了能够限制实例化,我们需要提供私有构造器。什么?私有构造器?没听过,就是私有构造器,别忘了,单例模式还要提供一个全局访问点呢,我们就用这个全局访问点来创建对象。看看它的类图吧,
在这个类中,i是一些无关紧要的变量,这个变量仅仅的存在仅仅是为了说明单例模式可以有自己的变量和方法。
实现代码:
public class Singleton { int i;//测试变量 public int I { get { return i; } set { i = value; } } //静态本类别私有成员变量 static private Singleton uniqueInstance = null; //私有的构造器--只有类内可以调用 private Singleton() { } //静态公有接口--实例化对象并返回 //如果我们不需要这个实例,它就永远不会被实例化,这就是“延迟实例化” static public Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); uniqueInstance.i = 0; } return uniqueInstance; } }
单例类有一个私有的本类别的实例,还有一个私有的构造器,那个唯一的全局访问点就是getInstance()方法,这个方法在创建对象之前,必须先判断这个唯一的实例是否已经存在了,以确保我们始终只有一个类对象。
测试代码:
static void Main(string[] args) { Singleton single = Singleton.getInstance(); single.I = 5; Console.WriteLine(single);//输出所属类别 Singleton single0 = Singleton.getInstance(); single0.I = 10; Console.WriteLine(single0.I); Console.WriteLine(single.I); Console.ReadKey(); }
可能,你也发现了,这个章节的标题是“单例模式(单线程)”,难道多线程会出什么问题吗?是的!这个代码只针对单线程,一旦有多个线程来执行这段代码,
由于getInstance()方法的操作次序和uniqueInstance的值可能在执行的时候发生重叠(用操作系统的知识解决),就会使得单例失效,还有可能产生意想不到的后果,如:
两个线程,线程1和线程2,当线程1执行到if (uniqueInstance == null)时,满足条件,实例化uniqueInstance,但是在实例化之前,线程2也恰好执行到if (uniqueInstance == null),这时候uniqueInstance还是null,也就是说线程2也会实例化一个uniqueInstance,这样,单例就失效了。别担心,我们将在下一节给出解决方案。