📌 单例模式一句话理解
保证一个类只有一个实例,全局都能访问到它。
🎯 只需记住这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. 静态方法(全局获取)
选择方案三选一:
要简单:饿汉式
要优雅:静态内部类
要性能:双重检查锁
🎯 实战建议
如果你刚学单例模式:
- 先用饿汉式 - 最简单不易错
- 理解原理后 - 尝试静态内部类
- 需要优化时 - 考虑双重检查锁
实际项目中:
- 90% 的情况用饿汉式就够了
- 配置类、工具类、连接池适合单例
- 不要滥用,只有真正需要全局唯一时才用
记住:单例模式的核心就是控制对象的创建,确保全局只有一个实例!