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

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

相关推荐
实名上网宋凯宣8 小时前
Django
后端·python·django
利威尔xu9 小时前
Go IM 源码实战(14):本地缓存快 3000 倍,失效却难 10 倍
后端·缓存·微服务·面试·golang
逃逸线LOF10 小时前
Ribbon负载均衡原理(Irule组件、源码分析)
后端·spring cloud·ribbon
慢云智慧空间10 小时前
从设备智能到空间理解,空间智能终端解决方案商如何重新定义行业标准
后端
利威尔xu10 小时前
Go IM 源码实战(13):30 个会话只有 2 个红点,未读数错在三条路径
redis·后端·微服务·面试·golang
薛定谔的猫-菜鸟程序员11 小时前
软件架构设计师开发资料大全(从入门到精通)
后端·python·系统架构·flask·架构设计师
IT_陈寒13 小时前
SpringBoot多环境配置把我坑惨了,这个踩坑经验你最好看看
前端·人工智能·后端
码事漫谈13 小时前
DeepSeek 搞了个 "Super-agent",但不是超级智能
后端
吴凡wudianmei13 小时前
从 0 搭一个 AI Agent(四):SSE 跑通之后,三处“契约错配”与它们的修复边界
前端·后端·aigc
小兔子13 小时前
defer 的参数在写下那一刻就求值了,循环里这样写会踩坑
后端