Java 单例设计模式(Singleton Pattern)指南

📌 单例模式一句话理解

保证一个类只有一个实例,全局都能访问到它。

🎯 只需记住这3种实现(按推荐顺序)

1. 饿汉式(最简单,最常用)

java

csharp 复制代码
public class Singleton {
    // 1. 自己创建自己(static + final)
    private static final Singleton INSTANCE = new Singleton();
    
    // 2. 私有构造方法(关键!不让别人new)
    private Singleton() {}
    
    // 3. 提供获取方法
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

特点

  • ✅ 最简单
  • ✅ 线程安全
  • ❌ 启动时就创建,可能浪费资源

2. 双重检查锁(性能好)

java

csharp 复制代码
public class Singleton {
    // volatile防止指令重排
    private static volatile Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {                     // 第一次检查
            synchronized (Singleton.class) {        // 加锁
                if (instance == null) {             // 第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

特点

  • ✅ 延迟创建(需要时才创建)
  • ✅ 线程安全
  • ✅ 高性能

3. 静态内部类(推荐)

java

csharp 复制代码
public class Singleton {
    private Singleton() {}
    
    // 静态内部类
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

特点

  • ✅ 延迟创建
  • ✅ 线程安全
  • ✅ 实现优雅

🚀 快速选择指南

场景 推荐方案 原因
简单项目 饿汉式 最简单,不易出错
需要延迟创建 静态内部类 优雅,线程安全
性能要求高 双重检查锁 延迟创建,性能好
绝对要安全 枚举 防止反射破坏

💡 实际应用示例

1. 配置管理类(最常用场景)

java

typescript 复制代码
// 配置文件管理器
public class ConfigManager {
    private static final ConfigManager INSTANCE = new ConfigManager();
    
    private Map<String, String> configs = new HashMap<>();
    
    private ConfigManager() {
        // 加载配置文件
        configs.put("db.url", "localhost:3306");
        configs.put("db.user", "root");
        configs.put("app.name", "MyApp");
    }
    
    public static ConfigManager getInstance() {
        return INSTANCE;
    }
    
    public String getConfig(String key) {
        return configs.get(key);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        // 全局都能访问同一个配置管理器
        String dbUrl = ConfigManager.getInstance().getConfig("db.url");
        System.out.println("数据库地址: " + dbUrl);
    }
}

2. 数据库连接池

java

csharp 复制代码
// 简易连接池
public class ConnectionPool {
    private static ConnectionPool instance;
    private List<Connection> connections;
    
    private ConnectionPool() {
        // 初始化连接池
        connections = new ArrayList<>();
        // ... 创建连接
    }
    
    public static synchronized ConnectionPool getInstance() {
        if (instance == null) {
            instance = new ConnectionPool();
        }
        return instance;
    }
    
    public Connection getConnection() {
        // 获取连接逻辑
        return null;
    }
}

⚠️ 常见错误

错误1:忘记私有构造器

java

csharp 复制代码
// ❌ 错误:构造器是public,别人可以new
public class WrongSingleton {
    private static WrongSingleton instance;
    
    public WrongSingleton() {  // 应该是 private!
    }
    
    // ...
}

错误2:非线程安全的懒汉式

java

csharp 复制代码
// ❌ 错误:多线程下可能创建多个实例
public class UnsafeSingleton {
    private static UnsafeSingleton instance;
    
    private UnsafeSingleton() {}
    
    public static UnsafeSingleton getInstance() {
        if (instance == null) {  // 线程不安全!
            instance = new UnsafeSingleton();
        }
        return instance;
    }
}

📝 记忆口诀

text

markdown 复制代码
单例模式三要素:
1. 私有构造器(不让new)
2. 静态实例(自己持有)
3. 静态方法(全局获取)

选择方案三选一:
要简单:饿汉式
要优雅:静态内部类
要性能:双重检查锁

🎯 实战建议

如果你刚学单例模式:

  1. 先用饿汉式 - 最简单不易错
  2. 理解原理后 - 尝试静态内部类
  3. 需要优化时 - 考虑双重检查锁

实际项目中:

  • 90% 的情况用饿汉式就够了
  • 配置类、工具类、连接池适合单例
  • 不要滥用,只有真正需要全局唯一时才用

记住:单例模式的核心就是控制对象的创建,确保全局只有一个实例!

相关推荐
啥都学点的程序员34 分钟前
python项目调用shardingsphere时,多进程情况下,shardingsphere配置的连接数会乘以进程数
后端
guchen6634 分钟前
C# 闭包捕获变量的经典问题分析
后端
Lear35 分钟前
Lombok全面解析:极致简化Java开发的神兵利器
后端
啥都学点的程序员35 分钟前
小坑记录:python中 glob.glob()返回的文件顺序不同
后端
Airene36 分钟前
spring-boot 4 相比 3.5.x 的包依赖变化
spring boot·后端
用户35442543654037 分钟前
别再裸奔了!你的 Spring Boot @Async 正在榨干服务器资源
后端
虎子_layor38 分钟前
小程序登录到底是怎么工作的?一次请求背后的三方信任链
前端·后端
SimonKing1 小时前
学不动了,学不动,根本学不动!SpringBoot4.x又来了!
java·后端·程序员
华仔啊1 小时前
SpringBoot + MQTT 如何实现取货就走的智能售货柜系统
java·后端