本文介绍设计模式中的单态(Singleton)模式的概念,用法,以及实际应用中怎么样使用Singleton模式进行开发。
Singleton的概念
Singleton模式是一种对象创建型模式,使用Singleton模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。
其实,GoF对Singleton模式的定义是:保证一个类只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。
为什么要使用Singleton模式呢?
在应用系统开发中,我们常常有以下需求:
- 在多个线程之间,比如servlet环境,共享同一个资源或者操作同一个对象
- 在整个程序空间使用全局变量,共享资源
- 大规模系统中,为了性能的考虑,需要节省对象的创建时间
等等
因为Singleton模式可以保证为一个类只生成唯一的实例对象,所以这些情况,Singleton模式就派上用场了。
Singleton模式的实现
Singleton模式是设计模式中相对比较简单的模式之一。理解以及使用方法都比较简单。
Singleton模式有多个实现方法。但目前,每一种都存在或多或少的问题。
下面我们将给出几种实现方法,同时对它们加以比较。
第一种方法:这是一种最简单的实现方法。但是一种相对有效的实现方法。现在,一般推荐这一种方法作为Singleton模式的实现方法。
//1)使用final关键字修改class,防止子类继承
public final class Singleton {
//2)Singleton自身唯一实例instance
private static final Singleton instance = new Singleton();
//3)private构造方法。防止外部调用者使用new创建新的实例
private Singleton(){};
//4)提供唯一实例的全局访问点
public static Singleton getInstance(){
return Singleton.instance;
}
...
}
注意上述1),2),3),4)部分,这是Singleton模式实现的几个关键。
我
们注意到,这种方法没有对instance = new
Singleton()部分作同期化操作,但考虑到Singleton实例的生成只是在最初被调用时才执行一次,如果我们在调用时适当处理一下,比如在程
序的统一初期化时(SERVLET环境的情况下可以在容器被初始化时如SevletListener里)调用一下Singleton,就不会存在线程安全
问题。
第二种方法:public final class Singleton {
private static Singleton instance;
private Singleton(){};
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
该方法把Singleton实例生成放到了getInstance方法里,同时使用synchronized解决了线程安全问题。
但如果在高并发的应用系统中,大量的线程在调用getInstance时会受到阻塞,系统的性能将受到严重影响。
第三种方法:public final class Singleton {
private static Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance == null){
synchronized (this) {
//double-check
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
该方法也叫double-check(双重检查)方法,把线程同步synchronized放到只会被执行一次的同步块里。该方法虽然解消了性能瓶颈问题,但该方法被指出并不是线程安全的(不同步的情况下引用类型不是线程安全的)。
第四种方法:public final class Singleton {
private volatile static Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance == null){
synchronized (this) {
//double-check
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
该方法在第三种方法的基础上,为Singleton instance的定义加上volatile关键字修饰,该方法也被称为double-check volatile方法。但该方法却依奈不同的编译器。也就是说,在某些编译环境中,第四种方法也是非线程安全的。