一个类有且仅有一个实例,并且自行实例化向整个系统提供,即为单例模式。
单例模式的目的是为了限制对象的实例个数,如果为一个,则为单例,否则如果实例个数为有限个,则为多例。
单例模式一般选择将默认构造函数访问限制为私有访问。
然后提供一个新的公开或protected新建实例的方法。
下面以Java,写几种常用的形式。
1.懒汉,线程不安全。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
如果想要使其线程安全,一种简单的方法是getInstance方法加入Synchronized限制符。但缺点也很明显,就是效率极低,因为大部分时间并不需要同步。
2.饿汉
public class Singleton {
private Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return this.instance;
}
}
优点是使用ClassRoader机制,避免了多线程同步问题。不过,实例在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化实例显然没有达到lazy loading的效果。
3.枚举
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
这是一种不错的写法,不过因为枚举的使用并不多,所以如果是合作项目就最好不要这么写啦。
4.静态内部类写法
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种写法的好处是既使用classloader机制实现了线程安全,也实现了懒汉,比较推荐这种写法。
5.多重校验锁版本
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
实现了多重线程锁,不多赘述。
如果想要实现多例模式,一个简单的方法是使用工厂模式来进行实例选择生成。工厂模式,下次再说。