单例模式,是一种经常使用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。经过单例模式能够保证系统中,应用该模式的一个类只有一个实例。即一个类只有一个对象实例。git
一、单例类只能有一个实例。
二、单例类必须本身建立本身的惟一实例。
三、单例类必须给全部其余对象提供这一实例github
说到代码实现,主要是3点
1.私有静态变量
2.私有化构造函数
3.静态的对象获取方法
相信看到这的时候你内心就有个答案了,看看和下面的所谓懒汉模式的代码是否是同样。设计模式
/// <summary> /// 懒汉,线程不安全 /// </summary> public class Singleton1 { private static Singleton1 _singleton = null;//私有静态变量 private Singleton1() { }//私有化构造函数 public static Singleton1 GetSingleton()//静态的对象获取方法 { if (_singleton == null)//保证为空才建立 { _singleton = new Singleton1(); } return _singleton; } }
若是这个答案和你想的同样,并一直也是这样用的,那只能说too young to simple,此方法其实有俩方面的问题,首先是线程不安全,若是同一时间,多个线程同时获取实例,则会出现获取到不一样的实例,所谓的单例也就成了线程内单例,明显不对,解决办法往下看。安全
/// <summary> /// 懒汉,线程安全 /// </summary> public class Singleton2 { private static Singleton2 _singleton = null; private static object _lock = new object(); private Singleton2() { } public static Singleton2 GetSingleton() { lock (_lock)//保证线程安全 { if (_singleton == null)//保证为空才建立 { _singleton = new Singleton2(); } return _singleton; } } }
话很少说,看过代码的你多半你也会说一句,加锁大法好.到这咱们基本上算是实现了,可是咱们看看这个锁,虽然解决了多个实例对象问题,可是该方式运行效率却很低,下一个线程想要获取对象,就必须等待上一个线程释放锁以后,才能够继续运行,但实际上对象大部分状况是已经存在了的并不须要new,所以对上个方法作了个优化。函数
/// <summary> /// 懒汉优化 /// </summary> public class Singleton3 { private static Singleton3 _singleton = null; private static object _lock = new object(); private Singleton3() { } public static Singleton3 GetSingleton() { if (_singleton == null)//保证对象初始化以后,线程不须要等待锁 { lock (_lock)//保证线程安全 { if (_singleton == null)//保证为空才建立 { _singleton = new Singleton3(); } } } return _singleton; } }
到这咱们想要的单例模式基本算ok了,码得我本身都累,想一想设计模式这么多年的沉淀,就没有简单点的写法么?答案固然是确定有的,从实现方法的命名也能够看出,除了懒汉模式,还有对应的饿汉模式,相对来讲写法比较简单。优化
/// <summary> /// 饿汉模式1 /// </summary> public class Singleton4 { private static Singleton4 _singleton = null; private Singleton4() { } /// <summary> /// 静态构造函数,由CLR调用,在使用以前被调用,并且之调用一次 /// </summary> static Singleton4() { _singleton = new Singleton4(); } public static Singleton4 GetSingleton() { return _singleton; } } /// <summary> /// 饿汉模式2 /// </summary> public class Singleton5 { /// <summary> /// 静态变量:会在类型第一次使用的时候初始化,并且只初始化一次 /// </summary> private static Singleton5 _singleton = new Singleton5(); private Singleton5() { } public static Singleton5 GetSingleton() { return _singleton; } }
以上俩种方式,我我的认为是等价的,一个应用了静态变量,一个用的静态构造函数。虽然写法相对简单,不过,instance 在类装载时就实例化,虽然致使类装载的缘由有不少种,在单例模式中大多数都是调用 getInstance 方法, 可是也不能肯定有其余的方式(或者其余的静态方法)致使类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。嗨,有问题总得解决,看看下面。线程
public class Singleton6 { private static class SingletonHolder { internal static Singleton6 _singleton = new Singleton6(); } private Singleton6() { } public static Singleton6 GetSingleton() { return SingletonHolder._singleton; } }
这种方式一样利用了静态变量的机制来保证初始化 instance 时只有一个线程,同时又解决了lazy loading。由于 SingletonHolder 类没有被主动使用,只有经过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,若是实例化 instance 很消耗资源,因此想让它延迟加载,另一方面,又不但愿在 Singleton 类加载时就实例化,这个时候,这种方式相对来讲比较实用。设计
通常状况下,懒汉优化模式更多的是让咱们从头出发,理解单例模式的运行过程和实现思路,建议使用饿汉方式(Singleton4/Singleton5)。只有在要明确实现 lazy loading 效果时,才会使用登记模式。code
事实上,经过反射机制是可以实例化构造方法为private的类的,那基本上会使全部的单例实现失效。因此咱们这里不考虑反射的状况
下载源码对象