单例模式是设计模式中使用最为普遍的模式之一。它是一种对象创建模式,用于产生一个对象的具体实例,确保系统中一个类只产生一个实例。在Java中这样的行为能带来两大好处:
- 对于频繁使用的对象,可以省略new操作花费的时间,这对于那些重量级的对象而言,是非常可观的一笔系统开销;
- 由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。
下面将介绍常用的三种创建单例模式的方式:
1:
public class Singleton {
private Singleton() {}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
这种单例模式的性能是非常好的 getInstance()方法只是简单的返回instance 并没有任何锁操作,因此它在并行程序中,会有良好的表现。但是这种方式有一点明显不足,就是Singleton构造函数,或者说Singleton实例在什么时候创建是不受控制的。对于静态成员instance,它会再类第一次初始化的时候被创建,这个时刻并不一定是getInstance()方法第一次被调用的时候。如果觉得这个小小的不足并不重要,我认为这种单例模式是一种不错的选择,它容易实现,易读而且性能优越。
2:
public class LazySingleton {
private LazySingleton() {
}
private static LazySingleton instance = null;
public static synchronized LazySingleton getInstance() {
if (instance == null)
instance = new LazySingleton();
return instance;
}
}
这种方式会再第一次调用时,创建单例对象。为了防止对象被多次创建,需要用synchronized进行方法同步。这种实现的好处是,充分利用了延迟加载,只在真正需要是创建对象。但坏处也很明显,并发环境下加锁,竞争激烈的场合对性能产生一定的影响。
3:
public class StaticSingleton {
private StaticSingleton() {
}
private static class SingletonHolder {
private final static StaticSingleton instance = new StaticSingleton();
}
public static StaticSingleton getInstance() {
return SingletonHolder.instance;
}
}
这种方式实现的单例同时拥有前两种方式的优点。首先getInstance()方法中没有锁,这使得在高并发环境下性能优越。其次,只有在getInstance()方法被第一次调用时,StaticSingleton的实例才会被创建。因为这种方式巧妙的使用了内部类和类的初始化方式。内部类SingletonHolder被声明为private,这使得我们不可能在外部访问并初始化它。而我们只可能在getInstance()内部对SingletonHolder类进行初始化,利用虚拟机的类初始化机制创建单例。