用私有构造器或者枚举类型强化Singleton属性
光构建单例对象还是不够的,还要保证其唯一性。
书中未介绍多线程下的单例实现,在最后我会拓展一下。
使用私有构造器
静态 final 字段
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
// 防止反射创建新实例
if (INSTANCE != null) {
throw new IllegalStateException("Already initialized");
}
}
public void leaveTheBuilding() {
// 业务方法
}
}
优点:
-
简单明了
-
线程安全(类加载时初始化)
缺点:
- 可以通过反射破坏单例(需要构造器中检查防止)
静态工厂方法
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() {
if (INSTANCE != null) {
throw new IllegalStateException("Already initialized");
}
}
public static Elvis getInstance() {
return INSTANCE;
}
public void leaveTheBuilding() {
// 业务方法
}
// 防止反序列化创建新实例
private Object readResolve() {
return INSTANCE;
}
}
优点:
-
更灵活,可以改为非单例而不改变 API
-
可以实现泛型单例工厂
-
可以通过方法引用作为supplier:Elvis::getInstance
缺点:
- 同样需要处理反射和反序列化问题
使用枚举类型
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() {
// 业务方法
}
// 其他方法...
}
优势:
-
绝对防止多实例化
枚举由 JVM 保证只会初始化一次
天生线程安全 -
防止反射攻击
枚举类型有特殊的反射处理,不能通过反射创建实例
其他方式的私有构造器可能被反射绕过 -
自动处理序列化
枚举实例序列化和反序列化不会创建新对象
其他方式需要实现 readResolve() 方法防止反序列化创建新实例 -
代码简洁
几行代码就能实现完整的单例功能
多线程下的单例
Enum
Enum天生线程安全且保证单例,同时也能防止反射等。就不多介绍了。
双重校验锁
public class Singleton {
// 使用 volatile 确保可见性和禁止指令重排序
private static volatile Singleton instance;
private Singleton() {
if (instance != null) {
throw new IllegalStateException("Already initialized");
}
}
public static Singleton getInstance() {
// 第一次检查(不加锁)
if (instance == null) {
synchronized (Singleton.class) {
// 第二次检查(加锁后)
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
volatile 防止指令重排和保证可见性。
静态内部类
public class Singleton {
private Singleton() {
if (Holder.INSTANCE != null) {
throw new IllegalStateException("Already initialized");
}
}
// 静态内部类在第一次被引用时才会加载
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
// 防止反序列化破坏单例
private Object readResolve() {
return Holder.INSTANCE;
}
}
利用静态内部类的特性进行单例的实现。
- 静态内部类使用时才加载
- 同时类加载机制线程也安全
- 性能好,无需同步机制的开销
即时初始化
public class Singleton {
// 类加载时立即初始化
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
if (INSTANCE != null) {
throw new IllegalStateException("Already initialized");
}
}
public static Singleton getInstance() {
return INSTANCE;
}
}
在类加载时创建INSTANCE单例对象。
- 饿汉式,不使用的话会造成性能浪费。

被折叠的 条评论
为什么被折叠?



