1. 饿汉式单例完整代码(基础版)
java
// 饿汉式单例:类加载时就创建实例
public class EagerSingleton {
// 关键点1:静态私有变量,类加载时初始化实例
// static:属于类,全局唯一;final:确保实例不可被替换;private:禁止外部直接访问
private static final EagerSingleton INSTANCE = new EagerSingleton();
// 关键点2:私有化构造器,阻止外部通过new创建实例
private EagerSingleton() {
// 可以在构造器中添加初始化逻辑(如初始化资源)
System.out.println("饿汉式单例实例被创建了");
}
// 关键点3:公开静态方法,提供全局访问点
public static EagerSingleton getInstance() {
return INSTANCE; // 直接返回预创建的实例
}
// 测试方法:验证实例唯一性
public void doSomething() {
System.out.println("当前实例地址:" + this);
}
// 主方法测试
public static void main(String[] args) {
// 尝试创建多个实例
EagerSingleton s1 = EagerSingleton.getInstance();
EagerSingleton s2 = EagerSingleton.getInstance();
// 调用方法,观察实例地址是否相同
s1.doSomething(); // 输出:当前实例地址:EagerSingleton@xxxxxxx
s2.doSomething(); // 输出:当前实例地址:EagerSingleton@xxxxxxx(与s1相同)
// 验证:s1和s2是否为同一个对象
System.out.println("s1 == s2 ? " + (s1 == s2)); // 输出:true(证明唯一)
}
}
2. 运行结果解析
- 程序启动时,
EagerSingleton类加载,会立即执行new EagerSingleton(),打印 "饿汉式单例实例被创建了"(类加载阶段初始化)。 - 调用
getInstance()两次,返回的s1和s2地址完全相同(==结果为true),证明全局只有一个实例。 - 无法通过
new EagerSingleton()创建实例(构造器私有,编译报错),确保了实例唯一性。
3. 多线程环境下的线程安全测试
饿汉式天生线程安全,因为类加载过程由 JVM 保证同步,以下代码验证:
java
public class EagerSingletonThreadTest {
public static void main(String[] args) {
// 启动10个线程,同时获取实例
for (int i = 0; i < 10; i++) {
new Thread(() -> {
EagerSingleton instance = EagerSingleton.getInstance();
System.out.println("线程" + Thread.currentThread().getId() + "获取的实例:" + instance);
}).start();
}
}
}
运行结果:所有线程打印的实例地址完全相同,证明多线程环境下不会创建多个实例(线程安全)。
4. 饿汉式的局限性示例(资源浪费场景)
如果单例实例初始化成本高(如加载大文件),但程序可能用不到,会浪费资源:
java
public class ResourceHeavyEagerSingleton {
// 假设初始化需要加载100MB的配置文件(模拟高成本)
private static final ResourceHeavyEagerSingleton INSTANCE = new ResourceHeavyEagerSingleton();
private ResourceHeavyEagerSingleton() {
System.out.println("加载100MB配置文件...(耗时操作)");
}
public static ResourceHeavyEagerSingleton getInstance() {
return INSTANCE;
}
public static void main(String[] args) {
System.out.println("程序启动,但暂时不需要用这个单例...");
// 此时,即使没调用getInstance(),实例也已创建并加载了资源(浪费)
}
}
运行结果:程序启动后,会直接打印 "加载 100MB 配置文件...(耗时操作)",即使从未使用该实例,资源已被消耗。
总结
饿汉式单例通过类加载时初始化静态实例 + 私有构造器 + 静态访问方法的组合,实现了:
- 实例唯一性(禁止外部创建,全局仅一个);
- 线程安全性(JVM 类加载机制保证);
- 简单直接的实现(无需处理同步逻辑)。
但需注意:如果实例初始化成本高且可能不被使用,会造成资源浪费,这种场景下需考虑懒汉式等其他实现。