public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton()l
private EagerSingleton() {
// 私有构造函数
}
public static EagerSingleton getInstance() {
return instance;
}
}
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
// 私有构造函数
}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
指令重排序:指令重排序是现代处理器为了提高性能锁采取的一种优化手段。在计算机执行指令时,处理器可能会对指令进行重排序,以充分利用处理器资源并提高执行效率。然后,指令重排序可能会导致程序的行为与预期不符,特别是在多线程环境下。
在单例模式中,如果不小心处理,指令重排序可能会导致单例对象在多线程环境下出现问题。以双重检查锁定单例模式为例,如果不使用
volatile
关键字修饰单例对象,会存在指令重排序的风险。以下是指令重排序可能引发的问题:
- 初始化顺序问题:如果在多线程环境下,一个线程在第一次检查实例是否为 null 时发现它不为 null,但实际上这个实例还未完成初始化,这时另一个线程可能会拿到一个尚未完全初始化的实例
- 可见性问题:指令重排序可能会导致对共享变量的修改在不同线程中的可见性问题,一个线程修改了共享变量的值,但另一个线程看不到这个修改。
为了解决指令重排序带来的问题,可以通过一下方式来保证线程安全:
- 在需要的地方使用
volatile
关键字,确保变量的可见性。- 使用同步块或锁来保证代码的顺序执行。
- 使用线程安全的数据结构或工具类。
public class DoubleCheckedSingleton {
// 保证内存可见性
private static volatile DoubleCheckedSingleton instance;
private DoubleCheckedSingleton() {
// 私有构造函数
}
public static DoubleCheckedSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedSingleton();
}
}
}
return instance;
}
}
public class StaticInnerSingleton {
private StaticInnerSingleton() {
// 私有构造函数
}
private static class SingletonHolder {
private static final StaticInnerSingleton instance = new StaticInnerSingleton();
}
public static StaticInnerSingleton getInstance() {
return SingletonHolder.instance;
}
}
public enum EnumSingleton {
INSTANCE;
// 可以添加其他方法或属性
}