单例模式是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。以下是几种实现单例模式的常见方式,每种方式都有其特点和适用场景。
1. 懒汉式(线程不安全)
这种实现方式在第一次调用时创建实例,但不适用于多线程环境。
public class SingletonLazy {
private static SingletonLazy instance;
private SingletonLazy() {
// 私有构造函数
}
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
缺点:多线程环境下可能会创建多个实例。
2. 懒汉式(线程安全,使用synchronized)
通过在获取实例的方法上加锁保证线程安全。
public class SingletonLazySafe {
private static SingletonLazySafe instance;
private SingletonLazySafe() {
// 私有构造函数
}
public static synchronized SingletonLazySafe getInstance() {
if (instance == null) {
instance = new SingletonLazySafe();
}
return instance;
}
}
缺点:性能较低,每次访问都需要加锁。
3. 双重检查锁(DCL)
通过减少加锁范围,提升性能,同时保证线程安全。
public class SingletonDCL {
private static volatile SingletonDCL instance;
private SingletonDCL() {
// 私有构造函数
}
public static SingletonDCL getInstance() {
if (instance == null) {
synchronized (SingletonDCL.class) {
if (instance == null) {
instance = new SingletonDCL();
}
}
}
return instance;
}
}
优点:高效,线程安全,推荐使用。
4. 饿汉式
在类加载时就创建实例,线程安全。
public class SingletonEager {
private static final SingletonEager INSTANCE = new SingletonEager();
private SingletonEager() {
// 私有构造函数
}
public static SingletonEager getInstance() {
return INSTANCE;
}
}
5. 静态内部类
利用类加载机制实现延迟加载和线程安全。
public class SingletonStaticInner {
private SingletonStaticInner() {
// 私有构造函数
}
private static class Holder {
private static final SingletonStaticInner INSTANCE = new SingletonStaticInner();
}
public static SingletonStaticInner getInstance() {
return Holder.INSTANCE;
}
}
优点:线程安全,延迟加载,推荐使用。
6. 枚举实现(推荐)
通过枚举类型实现单例,是最优雅的方式之一,同时也是线程安全的。
public enum SingletonEnum {
INSTANCE;
public void doSomething() {
System.out.println("SingletonEnum is working!");
}
}
优点:防止反射和序列化破坏单例。
7. 防止反射攻击
对于非枚举的单例模式,可以通过在构造函数中添加防御逻辑来防止反射攻击。
public class SingletonWithReflectionSafe {
private static final SingletonWithReflectionSafe INSTANCE = new SingletonWithReflectionSafe();
private SingletonWithReflectionSafe() {
if (INSTANCE != null) {
throw new RuntimeException("Cannot create instance via reflection!");
}
}
public static SingletonWithReflectionSafe getInstance() {
return INSTANCE;
}
}
选择建议
简单线程安全:优先考虑静态内部类或双重检查锁。
最安全(防反射和序列化攻击):使用枚举实现。
性能不敏感、初始化成本低:可以使用饿汉式。