单例模式

导读

单例模式(Singleton Pattern)是一种创建型设计模式 ,它确保一个类在整个应用程序生命周期中只有一个实例存在,并提供一个全局访问点来获取该实例。

在 Java 中,常见的实现方式主要有两种:饿汉式(Eager Initialization)懒汉式(Lazy Initialization)。它们各有优缺点,适用于不同场景。

实现方式 是否延迟加载 是否线程安全 是否推荐
饿汉式 ❌ 否 ✅ 是 ✅ 推荐(简单场景)
懒汉式(无锁) ✅ 是 ❌ 否 ❌ 不推荐
懒汉式(synchronized) ✅ 是 ✅ 是 ⚠️ 可接受(性能略差)
双重检查锁定 ✅ 是 ✅ 是 ✅ 推荐
静态内部类 ✅ 是 ✅ 是 ✅ 推荐
枚举 ✅ 是 ✅ 是 ✅✅ 最推荐

🎯 应用场景

  • 数据库连接池管理
  • 日志记录器(如 Logger
  • 配置管理类(如 Properties
  • Spring 中的 Bean 默认就是单例模式

一、饿汉式(Eager Initialization)

特点 :类加载时立即创建实例(急切初始化)
优点 :线程安全,无需加锁(由 JVM 类加载机制保证)
缺点:可能造成资源浪费(未使用时也占用内存)

1. 基础实现(静态变量)

java 复制代码
public class EagerSingleton {
    // 类加载时初始化实例
    private static final EagerSingleton INSTANCE = new EagerSingleton();
    
    private EagerSingleton() {}  // 私有构造器
    
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
}

2. 静态代码块变体

java 复制代码
public class EagerSingleton {
    private static final EagerSingleton INSTANCE;
    
    static {
        try {
            INSTANCE = new EagerSingleton();
        } catch (Exception e) {
            throw new RuntimeException("初始化失败", e);
        }
    }
    
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
}

3. 枚举实现(终极方案)

java 复制代码
public enum EnumSingleton {
    INSTANCE;  // 单例实例
    
    public void doSomething() {
        // 业务方法
    }
}
// 使用:EnumSingleton.INSTANCE.doSomething();

优势

  • 绝对防止反射攻击
  • 自动处理序列化/反序列化
  • 线程安全
  • 代码最简洁(Java 官方推荐方式)

二、懒汉式(Lazy Initialization)

特点 :首次使用时创建实例(延迟初始化)
优点 :节省资源
缺点:需额外处理线程安全问题

1. 非线程安全基础版

java 复制代码
public class UnsafeLazySingleton {
    private static UnsafeLazySingleton instance;
    
    private UnsafeLazySingleton() {}
    
    public static UnsafeLazySingleton getInstance() {
        if (instance == null) {  // 线程不安全点
            instance = new UnsafeLazySingleton();
        }
        return instance;
    }
}

2. 线程安全同步方法版(低效)

java 复制代码
public class SynchronizedLazySingleton {
    private static SynchronizedLazySingleton instance;
    
    private SynchronizedLazySingleton() {}
    
    public static synchronized SynchronizedLazySingleton getInstance() {
        if (instance == null) {
            instance = new SynchronizedLazySingleton();
        }
        return instance;
    }
}

缺点:每次获取实例都同步,性能差

3. 双重检查锁定(DCL)版(高效线程安全)

java 复制代码
public class DoubleCheckedLockingSingleton {
    // volatile 禁止指令重排序
    private static volatile DoubleCheckedLockingSingleton instance;
    
    private DoubleCheckedLockingSingleton() {}
    
    public static DoubleCheckedLockingSingleton getInstance() {
        if (instance == null) {  // 第一次检查(无锁)
            synchronized (DoubleCheckedLockingSingleton.class) {
                if (instance == null) {  // 第二次检查(有锁)
                    instance = new DoubleCheckedLockingSingleton();
                }
            }
        }
        return instance;
    }
}

关键点

  • volatile 防止 JVM 指令重排序(避免返回未初始化的对象)
  • 两次判空确保单例

4. 静态内部类(Holder)模式(推荐)

java 复制代码
public class HolderSingleton {
    private HolderSingleton() {}
    
    private static class Holder {
        // 由 JVM 保证线程安全初始化
        static final HolderSingleton INSTANCE = new HolderSingleton();
    }
    
    public static HolderSingleton getInstance() {
        return Holder.INSTANCE;  // 首次调用时加载 Holder 类
    }
}

优势

  • 线程安全(JVM 类加载机制)
  • 懒加载(调用 getInstance() 时才初始化)
  • 无同步开销

五、选型建议

  1. 首选枚举方案(Java 5+)

    • 满足所有安全需求
    • 代码简洁明了(《Effective Java》推荐)
  2. 需要懒加载时

    • 静态内部类(平衡安全性与性能)
    • 避免使用基础同步方法(性能差)
  3. 明确需要饿加载

    • 简单场景用饿汉式
    • 需异常处理时用静态块变体
  4. 超高性能场景

    • 首选枚举饿汉式
    • 次选双重检查锁定(注意 volatile)

📌 设计原则:在满足需求的前提下,选择最简单的实现。单例模式已被认为是一种"反模式",过度使用会导致代码耦合度高、难以测试,建议结合依赖注入框架(如Spring)管理单例。

相关推荐
WindSearcher15 分钟前
大模型微调相关知识
后端·算法
考虑考虑30 分钟前
Jpa中的@ManyToMany实现增删
spring boot·后端·spring
yuan199971 小时前
Spring Boot 启动流程及配置类解析原理
java·spring boot·后端
洗澡水加冰2 小时前
n8n搭建多阶段交互式工作流
后端·llm
陈随易2 小时前
Univer v0.8.0 发布,开源免费版 Google Sheets
前端·后端·程序员
六月的雨在掘金2 小时前
通义灵码 2.5 | 一个更懂开发者的 AI 编程助手
后端
朱龙凯3 小时前
MySQL那些事
后端
Re2753 小时前
剖析 MyBatis 延迟加载底层原理(1)
后端·面试
Victor3563 小时前
MySQL(63)如何进行数据库读写分离?
后端
Cache技术分享3 小时前
99. Java 继承(Inheritance)
前端·后端