必须将构造方法设为private,才能从源头阻止new Singleton()调用,确保唯一实例;饿汉式类加载即初始化、线程安全但不延迟;懒汉式双重检查锁实现延迟与线程安全;静态内部类方式兼顾延迟加载和天然线程安全。

Java 中通过单例模式控制构造方法私有化,核心是用 private 修饰符封禁构造方法,再配合静态成员和静态工厂方法来统一提供唯一实例。这不是语法糖,而是对对象创建权的主动收编。
为什么必须把构造方法设为 private
只有构造方法私有,才能从源头阻止外部代码执行 new Singleton()。一旦允许 public 或包内可见的构造方法,就无法保证“唯一实例”这一根本约束。编译器会在编译期直接报错,比如:Singleton() has private access in Singleton,这种强制拦截比运行时校验更可靠。
饿汉式:类加载即初始化
利用 JVM 类加载机制的天然线程安全性,适合初始化开销小、必然使用的场景:
- 静态 final 字段在类加载时完成实例化,无需同步
- 构造方法保持 private,外部无法绕过 getInstance() 创建新对象
- 代码简洁,无延迟,但不支持按需加载
示例:
public class EagerSingleton {
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {} // 关键:私有化
public static EagerSingleton getInstance() { return INSTANCE; }
}
懒汉式(双重检查锁):延迟 + 线程安全
适用于初始化耗时、且不一定被使用的场景。私有构造方法仍是前提,所有实例化都必须走 getInstance() 路径:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
- 第一次调用时才创建实例,节省资源
- 用 volatile 修饰 instance 防止指令重排
- 外层 null 检查避免每次加锁,内层再次检查确保唯一性
示例:
public class LazySingleton {
private static volatile LazySingleton instance;
private LazySingleton() {} // 必须私有
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
静态内部类方式:兼顾延迟与安全
这是推荐的写法,既避免了同步开销,又天然支持延迟加载:
- SingletonHolder 类在首次调用 getInstance() 时才被加载
- JVM 保证类加载过程线程安全,无需手动加锁
- 构造方法仍为 private,彻底切断非法实例化路径
示例:
public class HolderSingleton {
private HolderSingleton() {} // 私有是底线
private static class SingletonHolder {
private static final HolderSingleton INSTANCE = new HolderSingleton();
}
public static HolderSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










