引子
单例模式是设计模式中使用很频繁的一种模式,在各种开源框架、应用系统中多有应用,在我前面的几篇文章中也结合其它模式使用到了单例模式。这里我们就单例模式进行系统的学习。并对有人提出的“单例模式是邪恶的”这个观点进行了一定的分析。
定义与结构
单例对象(Singleton)是一种常用的设计模式。在GOF书中给出的定义为:保证一个类仅有一个实例,并提供一个访问他的全局访问点。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
单例模式在实现上是非常的,客户可以通过方法得到类的对象,用一个类图可以更直观的表示:
单例模式的实现
在单例模式的实现上有几种不同的方式,我在这里将一一讲解。先来看一种方式,它在《java 与模式》中被称为饿汉式。
饿汉式
public class Singleton {
//在自己内部定义自己一个实例
//注意这是private 只供内部调用
private static Singleton instance = new Singleton();
//如上面所述,将构造函数设置为私有
private Singleton(){
}
//静态工厂方法,提供了一个供外部访问得到对象的静态方法
public static Singleton getInstance() {
return instance;
}
}
懒汉式
下面这种方式被称为懒汉式:
public class Singleton {
//和上面有什么不同?
private static Singleton instance = null;
//设置为私有的构造函数
private Singleton(){
}
//静态工厂方法
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进
if (instance==null)
instance=new Singleton();
return instance;
}
}
先让我们来比较一下这两种实现方式。
首先他们的构造函数都是私有的,彻底断开了使用构造函数来得到类的实例的通道,但是这样也使得类失去了多态性(大概这就是为什么有人将这种模式称作单态模式)。
在第二种方式中,对静态工厂方法进行了同步处理,原因很明显——为了防止多线程环境中产生多个实例;而在第一种方式中则不存在这种情况。
在第二种方式中将类对自己的实例化延迟到第一次被引用的时候。而在第一种方式中则是在类被加载的时候实例化,这样多次加载会照成多次实例化。但是第二种方式由于使用了同步处理,在反应速度上要比第一种慢一些。