饿汉模式,即认为单例对象在单例所在的类初始化时即实例化了。
因此无论该单例对象是否真正的被调用,都会进行实例化。
实例化的操作放在静态变量或者静态代码块中。
public class HungrySingleton {
private HungrySingleton(){};
private final static HungrySingleton hungrySingleton = new HungrySingleton();
public static HungrySingleton getInstance(){
return HungrySingleton.hungrySingleton;
};
}
懒汉模式,单例对象在调用的时候,判断该单例对象是否为空,若空才进行实例化。
public class LazySingleton {
private LazySingleton(){};
private static LazySingleton lazySingleton = null;
public static LazySingleton getInstance(){
if(null == fullSingleton){
lazySingleton = new LazySingleton();
}
return LazySingleton.lazySingleton;
}
}
懒汉模式有线程安全问题。如果多个线程同时试图获取单例,且单例为空,那么可能会同时创建实例,即发生了多次的创建。
线程安全的懒汉模式:
public class SafeLazySingleton {
private SafeLazySingleton(){};
private static SafeLazySingleton safeLazySingleton = null;
public synchronized static SafeLazySingleton getInstance(){
if(null == safeLazySingleton){
safeLazySingleton = new SafeLazySingleton();
}
return SafeLazySingleton.safeLazySingleton;
};
}
有一种更优雅的方式可以解决线程安全问题。由于静态内部类才不发生调用时也不会进行初始化,故可以用来静态内部类的静态变量来存储实例。
public class InnerClassLazySingleton {
private InnerClassLazySingleton(){};
private static class InnerClassLazySingletonInstance{
static InnerClassLazySingleton innerClassLazySingletonInstance = new InnerClassLazySingleton();
}
public InnerClassLazySingleton getInstance(){
return InnerClassLazySingletonInstance.innerClassLazySingletonInstance;
}
}
多提一句,有看到资料提到使用枚举类也是一种不错的方法。JVM加载枚举类时使用ClassLoader方法,该方法使用同步代码块保证线程安全。
public enum EnumSingleton {
INSTANCE;
}