单例模式中的饿汉式

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()两次,返回的s1s2地址完全相同(==结果为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 配置文件...(耗时操作)",即使从未使用该实例,资源已被消耗。

总结

饿汉式单例通过类加载时初始化静态实例 + 私有构造器 + 静态访问方法的组合,实现了:

  1. 实例唯一性(禁止外部创建,全局仅一个);
  2. 线程安全性(JVM 类加载机制保证);
  3. 简单直接的实现(无需处理同步逻辑)。

但需注意:如果实例初始化成本高且可能不被使用,会造成资源浪费,这种场景下需考虑懒汉式等其他实现。

相关推荐
念越21 分钟前
数据结构:栈堆
java·开发语言·数据结构
淮北49442 分钟前
pip虚拟环境包的问题
开发语言·python·pip
千寻技术帮44 分钟前
10333_基于SpringBoot的家电进存销系统
java·spring boot·后端·源码·项目·家电进存销
dear_bi_MyOnly1 小时前
【多线程——线程状态与安全】
java·开发语言·数据结构·后端·中间件·java-ee·intellij-idea
常年游走在bug的边缘1 小时前
掌握JavaScript作用域:从函数作用域到块级作用域的演进与实践
开发语言·前端·javascript
jiaguangqingpanda1 小时前
Day36-20260204
java·开发语言
ctyshr1 小时前
C++编译期数学计算
开发语言·c++·算法
tb_first1 小时前
万字超详细苍穹外卖学习笔记4
java·spring boot·笔记·学习·spring·mybatis
打码的猿1 小时前
Qt对话框不锁死主程序的方法
开发语言·qt
努力写代码的熊大1 小时前
c++异常和智能指针
java·开发语言·c++