单例模式确保类唯一实例并提供全局访问点。1. 饿汉式在类加载时创建实例,线程安全但不支持懒加载。2. 懒汉式通过双重检查锁定实现懒加载,需配合volatile防止指令重排序。3. 静态内部类利用JVM类加载机制实现线程安全与懒加载,推荐使用。4. 枚举方式最安全,防止多线程、反射和反序列化破坏单例,适用于高安全场景。静态内部类和枚举为首选方案。
单例模式的核心目标是确保一个类在整个应用生命周期中只有一个实例,并提供一个全局访问点。在多线程环境下,多个线程可能同时尝试创建实例,因此必须保证线程安全。以下是几种正确实现线程安全单例模式的方案。
1. 饿汉式(静态常量)
在类加载时就创建实例,天然线程安全,因为类加载机制由JVM保证线程安全。
优点:实现简单,线程安全,执行效率高。
缺点:不是懒加载,即使未使用也会创建实例。
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
2. 懒汉式 + 双重检查锁定(Double-Checked Locking)
延迟加载,且通过 synchronized 和 volatile 关键字保证线程安全和防止指令重排序。
优点:懒加载,性能较好,仅在第一次创建时加锁。
注意:必须使用 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;
}
}
3. 静态内部类(推荐)
利用类加载机制保证线程安全,同时实现懒加载。只有在调用 getInstance 时才会加载内部类。
优点:既实现了懒加载,又无需加锁,代码简洁且高效。
原理:JVM 保证类的静态初始化过程是线程安全的。
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
4. 枚举方式(最安全)
Effective Java 推荐的方式,不仅能防止多线程问题,还能防止反序列化和反射攻击创建多个实例。
优点:写法简单,自动支持序列化,防止反射破坏单例。
适用场景:需要防止序列化/反射攻击的高安全性场景。
public enum Singleton {
INSTANCE;
public void doSomething() {
// 业务方法
}
}
使用:
Singleton.INSTANCE.doSomething();
基本上就这些。静态内部类和枚举是最推荐的实现方式,兼顾安全、性能和简洁。双重检查锁定也可用,但必须正确使用 volatile。饿汉式适合对启动速度不敏感的场景。
评论(已关闭)
评论已关闭