Java单例模式有几种实现方式
1. 饿汉式(Eager Initialization)
实现方式
- 静态常量:类加载时直接初始化实例。
public class Singleton {private static final Singleton INSTANCE = new Singleton();private Singleton() {}public static Singleton getInstance() { return INSTANCE; } }
- 静态代码块:在静态代码块中初始化实例。
public class Singleton {private static Singleton instance;static { instance = new Singleton(); }private Singleton() {}public static Singleton getInstance() { return instance; } }
特点
- 优点:线程安全,无需同步机制。
- 缺点:可能造成内存浪费(实例未使用即加载)。
- 适用场景:资源占用小且需立即初始化的场景。
- 引用:
2. 懒汉式(Lazy Initialization)
实现方式
- 线程不安全:未加锁,多线程可能创建多个实例。
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton(); // 多线程下可能重复创建}return instance;} }
- 同步方法:通过
synchronized
保证线程安全,但性能较差。public static synchronized Singleton getInstance() { ... }
特点
- 优点:延迟加载,节省内存。
- 缺点:同步锁导致性能瓶颈。
- 引用:
3. 双重检查锁定(Double-Checked Locking)
实现方式
通过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;}
}
特点
- 优点:线程安全且延迟加载,性能优于同步方法。
- 缺点:代码复杂度较高。
- 引用:
4. 静态内部类
实现方式
利用JVM类加载机制保证线程安全。
public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}
特点
- 优点:延迟加载,线程安全,无需同步锁。
- 缺点:需额外定义内部类。
- 引用:
5. 枚举(推荐)
实现方式
天然支持线程安全与序列化防护。
public enum Singleton {INSTANCE;public void doSomething() { /* ... */ }
}
特点
- 优点:
- 线程安全,无需同步机制。
- 防止反射与序列化攻击。
- 代码简洁,可扩展(可添加方法)。
- 缺点:不支持延迟加载。
- 引用:
实现方式对比
方式 | 线程安全 | 延迟加载 | 防反射/序列化 | 代码复杂度 | 推荐优先级 |
---|---|---|---|---|---|
饿汉式 | ✔️ | ❌ | ❌ | 低 | 4 |
懒汉式(同步) | ✔️ | ✔️ | ❌ | 中 | 3 |
双重检查锁定 | ✔️ | ✔️ | ❌ | 高 | 2 |
静态内部类 | ✔️ | ✔️ | ❌ | 中 | 1 |
枚举 | ✔️ | ❌ | ✔️ | 极低 | 最高 |
最佳实践建议
- 优先选择枚举:适用于大多数场景,兼顾安全与简洁。
- 延迟加载需求:使用静态内部类或双重检查锁定。
- 反射与序列化防护:枚举天然支持,其他方式需手动添加防御代码(如私有构造器校验、
readResolve()
方法)。