手写单例模式的六种实现方式详解
一、核心设计原则 实现单例模式需满足三个关键条件:
- 禁止外部直接创建实例,必须将构造函数设为私有;
- 实例的创建权归属类自身,通过内部逻辑完成初始化;
- 提供全局访问点,通过公共静态方法返回唯一实例。
二、常见实现方案对比
- 饿汉式 - 静态常量法(推荐) 类加载时即完成实例化,天然线程安全,适合初始化开销小的场景。
public class EagerSingleton {
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
- 饿汉式 - 静态代码块法 与上一种本质相同,仅初始化时机通过静态块控制,适用于需要复杂初始化逻辑的场景。
public class StaticBlockSingleton {
private static StaticBlockSingleton instance;
static {
instance = new StaticBlockSingleton();
}
private StaticBlockSingleton() {}
public static StaticBlockSingleton getInstance() {
return instance;
}
}
- 懒汉式 - 基础版本(不推荐) 延迟加载,但未加同步,多线程环境下可能产生多个实例。
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
- 懒汉式 - 同步方法版
使用
synchronized保证线程安全,但锁粒度大,性能较差。
public class SynchronizedLazySingleton {
private static SynchronizedLazySingleton instance;
private SynchronizedLazySingleton() {}
public static synchronized SynchronizedLazySingleton getInstance() {
if (instance == null) {
instance = new SynchronizedLazySingleton();
}
return instance;
}
}
- 双重检查锁定(推荐)
在保证线程安全的同时减少同步开销,关键在于
volatile修饰防止指令重排。
public class DoubleCheckSingleton {
private static volatile DoubleCheckSingleton instance;
private DoubleCheckSingleton() {}
public static DoubleCheckSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckSingleton.class) {
if (instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
- 静态内部类(最优解) 利用类加载机制实现延迟初始化,线程安全且无性能损耗,是现代Java项目中最优选择。
public class InnerClassSingleton {
private InnerClassSingleton() {}
private static class Holder {
private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
}
public static InnerClassSingleton getInstance() {
return Holder.INSTANCE;
}
}