Java单例模式
单例模式保证一个类只有一个实例,并提供全局访问点。
模式定义
意图:确保类只有一个实例,自行创建并提供全局访问。
适用场景:
- 配置管理器
- 日志记录器
- 数据库连接池
- 缓存管理器
实现方式
1. 饿汉式(推荐)
Java
public class Singleton {
// 类加载时就创建实例
private static final Singleton INSTANCE = new Singleton();
private Singleton() {} // 私有构造器
public static Singleton getInstance() {
return INSTANCE;
}
}
优点:实现简单、线程安全 缺点:类加载时就初始化,可能浪费资源
2. 懒汉式(不推荐)
Java
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // 线程不安全!
}
return instance;
}
}
问题:多线程环境下可能创建多个实例
3. 同步方法懒汉式
Java
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优点:线程安全 缺点:每次调用都同步,性能差
4. 双重检查锁(DCL)
Java
public class Singleton {
private volatile static Singleton instance; // volatile很重要
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查
instance = new Singleton();
}
}
}
return instance;
}
}
volatile作用:防止指令重排序,保证instance初始化完成后再返回。
5. 静态内部类(推荐)
Java
public class Singleton {
private Singleton() {}
// 静态内部类,延迟加载
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
优点:线程安全、延迟加载、无同步开销
6. 枚举(最佳方案)
Java
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("单例方法");
}
}
// 使用
Singleton.INSTANCE.doSomething();
优点:
- 线程安全
- 防止反射破坏
- 防止序列化破坏
- 代码简洁
各实现方式对比
| 方式 | 线程安全 | 延迟加载 | 性能 | 防反射 | 防序列化 |
|---|---|---|---|---|---|
| 饿汉式 | ✓ | ✗ | 好 | ✗ | ✗ |
| 懒汉式 | ✗ | ✓ | 好 | ✗ | ✗ |
| 同步方法 | ✓ | ✓ | 差 | ✗ | ✗ |
| 双重检查 | ✓ | ✓ | 好 | ✗ | ✗ |
| 静态内部类 | ✓ | ✓ | 好 | ✗ | ✗ |
| 枚举 | ✓ | ✓ | 好 | ✓ | ✓ |
防止反射破坏
Java
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
// 防止反射创建实例
if (INSTANCE != null) {
throw new IllegalStateException("单例已存在");
}
}
public static Singleton getInstance() {
return INSTANCE;
}
}
防止序列化破坏
Java
public class Singleton implements Serializable {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
// 反序列化时返回已有实例
protected Object readResolve() {
return INSTANCE;
}
}
实际应用示例
Java
// 配置管理器
public class ConfigManager {
private static final ConfigManager INSTANCE = new ConfigManager();
private Properties config = new Properties();
private ConfigManager() {
loadConfig();
}
public static ConfigManager getInstance() {
return INSTANCE;
}
public String get(String key) {
return config.getProperty(key);
}
private void loadConfig() {
try {
config.load(new FileInputStream("config.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意事项
私有构造器防止外部实例化
volatile 保证DCL的正确性
枚举是最安全、最简洁的实现
考虑序列化和反射攻击的防御
单例不适合需要继承的场景
要点总结
- 单例确保类只有一个实例,提供全局访问
- 饿汉式简单安全,静态内部类延迟加载
- 双重检查锁需配合volatile使用
- 枚举是最推荐的实现方式,防反射防序列化
- 私有构造器是单例的基础
📝 发现内容有误?点击此处直接编辑