以下是 Java 单例模式的 8 种经典实现,结合线程安全性、延迟加载、防反射等维度深度解析,并附应用场景对比表。以咖啡店店长为例通俗化讲解:
🔒 一、饿汉式(Eager Initialization)
public class CafeManager {
private static final CafeManager INSTANCE = new CafeManager(); // 开业前就选好店长
private CafeManager() {} // 禁止外部招聘新店长
public static CafeManager getInstance() {
return INSTANCE; // 直接返回唯一店长
}
}
原理:类加载时立即初始化(类似咖啡店装修时已确定店长)
优点:线程安全(JVM 类加载机制保证)、实现简单
缺点:可能浪费资源(店长闲置时也占着位置)
😴 二、懒汉式(线程不安全版)
public class CafeManager {
private static CafeManager instance;
private CafeManager() {}
public static CafeManager getInstance() {
if (instance == null) { // 临时招店长
instance = new CafeManager();
}
return instance;
}
}
原理:首次调用时创建实例(顾客上门才招店长)
缺点:多线程下可能创建多个店长(多个顾客同时下单招人)❌ 禁止生产使用
🔐 三、懒汉式(同步方法版)
public class CafeManager {
private static CafeManager instance;
private CafeManager() {}
public static synchronized CafeManager getInstance() {
if (instance == null) {
instance = new CafeManager();
}
return instance;
}
}
改进:
synchronized
锁方法保证线程安全(只允许一个顾客招聘店长)缺点:每次调用都加锁,性能差(每个顾客都要排队问店长在不在)
⚡ 四、双重检查锁(DCL 终极版)
public class CafeManager {
private static volatile CafeManager instance; // volatile 防指令重排
private CafeManager() {}
public static CafeManager getInstance() {
if (instance == null) { // 第一次检查:避免不必要的锁竞争
synchronized (CafeManager.class) {
if (instance == null) { // 第二次检查:确保唯一性
instance = new CafeManager();
}
}
}
return instance;
}
}
原理:两次判空 +
volatile
保证可见性与有序性(店长招聘室双重门禁)优点:线程安全 + 延迟加载 + 高性能(多数情况无需加锁)
适用:高并发场景(网红咖啡店高峰期)
📦 五、静态内部类(推荐)
public class CafeManager {
private CafeManager() {}
private static class ManagerHolder {
static final CafeManager INSTANCE = new CafeManager(); // 内部类持店长
}
public static CafeManager getInstance() {
return ManagerHolder.INSTANCE; // 首次调用时加载内部类
}
}
原理:利用类加载机制(当访问
ManagerHolder
时才初始化店长)优点:线程安全(JVM 保证类加载同步)、天然延迟加载、无锁高性能
Java 内存模型保证静态内部类加载仅一次
🏷️ 六、枚举式(最安全)
public enum CafeManager {
INSTANCE; // 枚举常量即单例
public void openCafe() {
System.out.println("咖啡店营业!");
}
}
// 使用:CafeManager.INSTANCE.openCafe();
原理:枚举类型天生单例(JVM 层保障)
优势:
绝对线程安全
自动防反射攻击(无法通过反射创建枚举)
自动处理序列化(反序列化不生成新对象)
Effective Java 作者推荐
🧵 七、ThreadLocal 式(线程级单例)
public class ThreadLocalManager {
private static final ThreadLocal<ThreadLocalManager> instance =
ThreadLocal.withInitial(ThreadLocalManager::new); // 每个线程独立店长
public static ThreadLocalManager getInstance() {
return instance.get();
}
}
原理:每个线程拥有独立实例(分店各自有店长)
适用场景:
线程上下文隔离(如数据库连接管理)
避免同步但非全局单例
⚛️ 八、CAS 原子操作式(无锁实现)
public class CASManager {
private static final AtomicReference<CASManager> INSTANCE =
new AtomicReference<>();
private CASManager() {}
public static CASManager getInstance() {
for (;;) {
CASManager instance = INSTANCE.get();
if (instance != null) return instance;
instance = new CASManager();
if (INSTANCE.compareAndSet(null, instance)) // CAS 原子操作
return instance;
}
}
}
原理:CAS(Compare-And-Swap)无锁更新(店长竞选投票机制)
优点:避免线程阻塞,高并发性能优
缺点:可能多次实例化(但仅存一个有效),实现复杂
🛡️ 单例模式防破坏技巧
📊 单例模式应用场景与选择指南
💡 黄金口诀: “一私一静一全局” —— 私有构造、静态实例、全局访问点 延迟加载选静态内部类,绝对安全用枚举!
通过这 8 种实现 + 防破坏技巧 + 场景对照表,可彻底掌握单例模式精髓。实际开发中优先选择 静态内部类(延迟加载)或 枚举(安全防护),避免过度设计。
评论区