单例模式
懒汉模式
懒汉模式即延迟加载,在需要用到该实例时进行实例化,在使用懒汉模式需要注意以下几点
- synchronized线程安全
- double check 保证只有一个线程创建成功
- 使用volatile禁止编译器对对象在实例化的过程中进行重排序
public class LazySingleton {
private volatile static LazySingleton singleton;
public static LazySingleton getLazySingleton() {
if (singleton == null) {
synchronized (LazySingleton.class) {
if (singleton == null) {
// 1.分配内存
// 2.初始化
// 3.引用赋值
singleton = new LazySingleton();
}
}
}
return singleton;
}
}
实例化对象并不是原子操作,可以分为三个步骤:
- 分配内存;
- 初始化对象
- 将内存地址赋值给引用
编译器在不影响程序执行结果的情况下,会对以上步骤进行指令重排序,可能将第二步和第三步进行替换;如果t1刚执行完第三步,准备执行第二步,此时t2进来判断singleton不为空,直接返回没有初始化的对象,导致程序异常。
饿汉模式
饿汉模式通过jvm类加载器实现的,在加载类时的初始化阶段就完成了类的初始化(即初始化阶段给类的静态变量赋值)。并且类加载器由双亲委派机制使用保证只会被加载一次,并且loadClass在加载类时使用synchronized保证线程安全
public class HungrySingleton {
private static HungrySingleton singleton = new HungrySingleton();
private HungrySingleton() {
//防止反射攻击
if (HungrySingleton.singleton != null) {
throw new RuntimeException("单例不允许创建多个实例");
}
}
public static HungrySingleton getSingleton() {
return singleton;
}
public static void main(String[] args) throws Exception {
HungrySingleton singleton = HungrySingleton.getSingleton();
//反射攻击实例
Constructor<HungrySingleton> constructor = HungrySingleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
HungrySingleton instance = constructor.newInstance();
System.out.println(instance == singleton);
}
}
静态内部类
- 本质上是利用类的加载机制来保证线程安全
- 只有在实际使用的时候,才会触发类的初始化,所以也是懒加载的一种形式。
public class InnerClassSingleton {
private static class InnerClassHolder {
private static InnerClassSingleton singleton = new InnerClassSingleton();
}
private InnerClassSingleton() {
if (InnerClassHolder.singleton != null) {
throw new RuntimeException("单例不允许创建多个实例");
}
}
public static InnerClassSingleton getSingleton() {
return InnerClassHolder.singleton;
}
}
枚举类型
- 天然不支持反射,且有自己的序列化机制
- 利用类加载机制保证线程安全
public enum EnumSingleton {
INSTANCE;
}
反序列化
指定方法来替换在反序列化创建的实例
比如在静态内部类实现的单例模式中添加如下方法
Object readResolve() {
return InnerClassHolder.singleton;
}
应用场景
源码级应用场景
- 饿汉模式:java.lang.Runtime
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
}
- 懒汉模式:org.springframework.core.ReactiveAdapterRegistry
public static ReactiveAdapterRegistry getSharedInstance() {
ReactiveAdapterRegistry registry = sharedInstance;
if (registry == null) {
synchronized (ReactiveAdapterRegistry.class) {
registry = sharedInstance;
if (registry == null) {
registry = new ReactiveAdapterRegistry();
sharedInstance = registry;
}
}
}
return registry;
}
- 反序列化时一个id对应一个实例org.springframework.beans.factory.support.DefaultListableBeanFactory.SerializedBeanFactoryReference
private Object readResolve() {
Reference<?> ref = serializableFactories.get(this.id);
if (ref != null) {
Object result = ref.get();
if (result != null) {
return result;
}
}
// Lenient fallback: dummy factory in case of original factory not found...
DefaultListableBeanFactory dummyFactory = new DefaultListableBeanFactory();
dummyFactory.serializationId = this.id;
return dummyFactory;
}
日常开发应用场景
- 线程池对象
- 工厂对象