单例模式出现反模式的情况
- 多线程环境下:如果在多线程环境中实现单例模式时没有采取合适的同步机制,可能会创建出多个实例。例如,在没有同步的双重检查锁定(DCL)实现中,由于指令重排序问题,可能导致一个线程看到未完全初始化的实例。
- 复杂对象状态管理:当单例对象的状态复杂且在不同模块中有频繁修改时,可能导致难以调试和维护。因为任何部分都可以修改单例的状态,使得程序的行为变得不可预测。
- 单元测试:单例模式可能会给单元测试带来困难。因为单例对象的状态可能在不同测试用例中相互影响,导致测试结果不稳定。
多线程环境下的问题及应对策略
- 问题:可能创建多个实例。在不加同步的情况下,多个线程同时进入创建实例的代码块,会各自创建一个实例,破坏单例的唯一性。
- 应对策略:
- 饿汉式单例:在类加载时就创建实例,避免多线程问题。代码如下:
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
- **懒汉式单例(同步方法)**:在获取实例的方法上加 `synchronized` 关键字,确保同一时间只有一个线程能进入该方法创建实例。代码如下:
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
- **双重检查锁定(DCL)**:在 `synchronized` 块内外都进行检查,减少同步带来的性能开销。同时,使用 `volatile` 关键字修饰实例变量防止指令重排序。代码如下:
public class DCLSingleton {
private volatile static DCLSingleton instance;
private DCLSingleton() {}
public static DCLSingleton getInstance() {
if (instance == null) {
synchronized (DCLSingleton.class) {
if (instance == null) {
instance = new DCLSingleton();
}
}
}
return instance;
}
}
- **静态内部类单例**:利用类加载机制实现延迟加载且线程安全。代码如下:
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {}
private static class SingletonHolder {
private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
- **枚举单例**:简洁且天然线程安全,还能防止反射和序列化破坏单例。代码如下:
public enum EnumSingleton {
INSTANCE;
// 可以添加其他方法和属性
}