单例模式(Singleton)的 5 种实现方式及最佳实践
一、懒汉式单例模式(线程安全但性能低,每次获取都加锁,性能差)
public class Singleton {
private static Singleton instance;
// 私有构造
private Singleton() {}
// 方法同步
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
二、饿汉式单例模式(线程安全但可能造成资源浪费,类加载时就初始化)
public class Singleton {
// 类加载时立即初始化
private static final Singleton instance = new Singleton();
// 私有构造
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
三、双重检查锁(兼顾延迟加载和线程安全,需volatile保证可见性和有序性)
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;
}
}
四、静态内部类(推荐方案,线程安全且延迟加载。static 变量是在所属类首次被访问时加载,静态内部类 InnerClass 是一个独立类,它的 static 变量不会因为 Singleton 类加载而初始化,只有调用 getInstance() 时,InnerClass 才会被 JVM 加载,这时 instance 才会被创建)
public class Singleton {
// 私有构造
private Singleton() {}
private static class InnerClass {
// 只有调用 getInstance() 时才加载 InnerClass
static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return InnerClass.instance;
}
}
五、枚举(最佳实践,防反射攻击和序列化问题。枚举的每个实例都是 全局唯一 的,由 JVM 在类加载时初始化,且无法通过反射或序列化破坏其唯一性)
public enum Singleton {
INSTANCE; // 天然单例
public void doSomething() {
// 方法实现
}
}
// 使用:Singleton.INSTANCE.doSomething();
Spring的 @Scope("singleton") 也是类似思想,但由容器管理而非代码控制