单例模式(Singleton Pattern)保证每个对象只拥有一个实例,而且不需要外部去实例化对象,从而减少创建多次对象时对内存的消耗,主要用于数据需要唯一性的场景,而单例模式的实现方式一般分为饿汉式和懒汉式
饿汉式:
/**
* 饿汉式单例实现
*/
public class EagerSingleton {
private static final EagerSingleton Instance=new EagerSingleton();
//私有化构造方法让外部无法通过new去创建实例
private EagerSingleton(){
}
//对外提供一个获取实例的方法
public static EagerSingleton getInstance() {
return Instance;
}
}
由上可见饿汉式是在类加载器加载的时候就将对象创建完毕,然后将对象的构造方法私有化,让外部无法直接通过new来创建实例,然后提供一个获取实例的getInstance()方法即可。这种方式实现的单例因为是类加载器加载时就创建好了对象所以不会出现线程安全,但是有点耗费内存资源,我们其实应该是在它使用的时候在去创建对象,下面介绍懒汉式的方法。
懒汉式
/**
* 简单懒汉式
*/
public class LazySingleton {
private static LazySingleton instance=null;
//私有化构造方法
private LazySingleton(){
}
//提供一个创建实例的方法
public synchronized static LazySingleton getInstance() {
if (null==instance){
instance=new LazySingleton();
}
return instance;
}
}
上面这种简单式的可以保证在多线程下安全的获取实例,但是每次获取都要加一次锁,我们知道加锁会耗费资源的,因此还有下面使用一种叫做双重校验锁(DCL,即 double-checked locking)
/**
* DCL的方式
*/
public class LazySingleton {
private volatile static LazySingleton instance=null;
//私有化构造方法
private LazySingleton(){
}
//提供一个创建实例的方法
public static LazySingleton getInstance() {
if (null==instance){
synchronized (LazySingleton.class){
if (null==instance){
instance=new LazySingleton();
}
}
}
return instance;
}
}
此方式在JDK1.5以前是不成立的,因为在之前多线程状态下LazySingleton 类与instance是无法预料谁先初始化,1.5以后新增了volatile 关键字,增加了数据的可见性,因此此方法目前是可行的。
登记式单例类可继承式