Skip to content
清晨的一缕阳光
返回

单例模式八种实现

单例模式八种实现

单例模式是最简单的设计模式,但实现方式多样,每种都有其适用场景。

一、什么是单例模式

单例模式 = 一个类只有一个实例 + 提供全局访问点

应用场景:
- 配置管理器
- 数据库连接池
- 日志记录器
- 线程池

二、八种实现方式

2.1 饿汉式(静态常量)

public class Singleton {
    // 类加载时创建
    private static final Singleton INSTANCE = new Singleton();
    
    // 私有构造
    private Singleton() {}
    
    // 全局访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

优点

缺点

2.2 饿汉式(静态代码块)

public class Singleton {
    private static final Singleton INSTANCE;
    
    static {
        INSTANCE = new Singleton();
    }
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

特点:与方式 1 类似,可在代码块中处理异常

2.3 懒汉式(线程不安全)

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton(); // 线程不安全
        }
        return instance;
    }
}

问题:多线程可能创建多个实例

2.4 懒汉式(线程安全)

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点:线程安全

缺点:性能低(每次都同步)

2.5 双重检查锁定(DCL)

public class Singleton {
    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;
    }
}

优点

关键

2.6 静态内部类

public class Singleton {
    private Singleton() {}
    
    // 静态内部类
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

优点

推荐:⭐⭐⭐⭐⭐

2.7 枚举(最简洁)

public enum Singleton {
    INSTANCE;
    
    // 可以添加方法
    public void doSomething() {
        // ...
    }
}

// 使用
Singleton.INSTANCE.doSomething();

优点

推荐:⭐⭐⭐⭐⭐

2.8 注册表(容器)

public class SingletonRegistry {
    private static Map<String, Object> registry = new ConcurrentHashMap<>();
    
    @SuppressWarnings("unchecked")
    public static <T> T getInstance(String name, Class<T> clazz) {
        return (T) registry.computeIfAbsent(name, key -> {
            try {
                return clazz.getDeclaredConstructor().newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }
}

适用场景:需要管理多个单例


三、对比总结

方式线程安全延迟加载性能推荐度
饿汉式⭐⭐⭐
懒汉式⭐⭐
DCL⭐⭐⭐⭐
静态内部类⭐⭐⭐⭐⭐
枚举⭐⭐⭐⭐⭐

四、单例破坏与防护

4.1 反射攻击

// 攻击普通单例
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton instance = constructor.newInstance(); // 创建新实例

// 防护(枚举)
// 枚举的构造器不能被反射调用

4.2 序列化攻击

// 攻击
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj"));
oos.writeObject(Singleton.getInstance());

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj"));
Singleton instance = (Singleton) ois.readObject(); // 新实例

// 防护
public class Singleton implements Serializable {
    // ...
    
    // 防止序列化破坏
    private Object readResolve() {
        return INSTANCE;
    }
}

4.3 克隆攻击

// 攻击
Singleton clone = (Singleton) instance.clone();

// 防护
@Override
protected Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException("Singleton cannot be cloned");
}

五、最佳实践

5.1 推荐使用枚举

// 最简洁、最安全
public enum Singleton {
    INSTANCE;
    
    private final DataSource dataSource;
    
    Singleton() {
        dataSource = createDataSource();
    }
    
    public DataSource getDataSource() {
        return dataSource;
    }
}

5.2 次选静态内部类

// 适用于需要继承的场景
public class Singleton {
    private Singleton() {}
    
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

5.3 避免使用懒汉式

// ❌ 不推荐
public static synchronized Singleton getInstance() {
    // 性能低
}

// ✅ 推荐
public static Singleton getInstance() {
    return Holder.INSTANCE;
}

六、Spring 中的单例

6.1 Spring 默认单例

// Spring Bean 默认单例
@Component
public class UserService {
    // Spring 管理,默认单例
}

// 配置作用域
@Scope("prototype") // 多例
@Scope("request")   // 请求级别
@Scope("session")   // 会话级别

6.2 Spring 单例 vs 单例模式

Spring 单例:
- 容器管理
- 可配置作用域
- 支持依赖注入

单例模式:
- 代码实现
- 固定单例
- 手动管理依赖

七、总结

单例模式核心要点:

实现方式优点缺点适用场景
枚举简洁、安全不能继承首选推荐
静态内部类延迟加载、安全代码稍多次选推荐
DCL性能好实现复杂特殊场景
饿汉式简单不延迟加载资源占用小

推荐使用枚举实现单例,简洁且安全,有效防止反射和序列化攻击。


分享这篇文章到:

上一篇文章
Go 数据类型系统详解
下一篇文章
Java 字符串详解