跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Java 单例模式详解:饿汉式与懒汉式实现对比

Java 单例模式的两种经典实现方式:饿汉式和懒汉式。饿汉式在类加载时创建实例,线程安全但可能浪费资源;懒汉式延迟加载,分为基础版、同步锁版和双重检查锁(DCL)版。文章通过代码示例和表格对比了各版本的线程安全性、性能及实现难度,并补充了使用枚举实现的推荐方案。

数字游民发布于 2026/3/28更新于 2026/7/1942 浏览
Java 单例模式详解:饿汉式与懒汉式实现对比

核心概念:单例模式

  • 目的:确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。
  • 应用场景:比如数据库连接池、线程池、日志对象、应用的配置类等。这些对象在程序中只需要一个实例即可,创建多个实例会浪费资源或导致行为异常。

饿汉式

核心思想:'饿',顾名思义,很饥饿,所以在类加载的时候就已经创建好实例,不管后面用不用,先创建了再说。 特点:

  • 线程安全:因为实例的创建是在类加载阶段完成的,这个阶段由 JVM 保证线程安全。
  • 加载慢,获取快:类一加载就初始化实例,可能会稍微拖慢启动速度,但获取实例对象的速度非常快。

代码示例:

public class SingletonEager { 
    // 1. 私有静态实例,在类加载时就直接创建 
    private static final SingletonEager INSTANCE = new SingletonEager(); 
    // 2. 私有构造函数,防止外部通过 new 关键字创建实例 
    private SingletonEager() {} 
    // 3. 公共的静态方法,用于获取唯一实例 
    public static SingletonEager getInstance() { 
        return INSTANCE; 
    } 
}

优点:实现简单,绝对线程安全。
缺点:如果这个实例非常耗费资源,但在整个程序运行过程中又可能用不到,就会造成资源的浪费。

懒汉式

核心思想:'懒',很懒惰,所以只有在第一次被用到的时候才创建实例。 特点:

  • 资源利用率高:只有在需要的时候才创建,避免了不必要的资源消耗。
  • 加载快,获取慢(第一次):类加载时不初始化,第一次调用 getInstance() 时才创建,所以第一次获取会稍慢。

基础版(非线程安全)

这个版本在多线程环境下会出问题。

public class SingletonLazy { 
    private static SingletonLazy instance; 
    // 不直接初始化 
    private SingletonLazy() {} 
    public static SingletonLazy getInstance() { 
        // 判断如果实例为空,则创建 
        if (instance == null) { 
            instance = new SingletonLazy(); 
            // 问题所在:多个线程可能同时进入这里 
        } 
        return instance; 
    } 
}

改进版(线程安全,使用 synchronized)

通过给方法加锁来解决线程安全问题,但效率较低。

public class SingletonLazySync { 
    private static SingletonLazySync instance; 
    private SingletonLazySync() {} 
    // 使用 synchronized 关键字,保证同时只有一个线程能进入该方法 
    public static synchronized SingletonLazySync getInstance() { 
        if (instance == null) { 
            instance = new SingletonLazySync(); 
        } 
        return instance; 
    } 
}

最优版(双重检查锁 DCL)

为了兼顾线程安全和效率,我们只在实例还没创建的时候进行同步。

public class SingletonLazyDCL { 
    // 使用 volatile 关键字,防止指令重排,保证可见性 
    private static volatile SingletonLazyDCL instance; 
    private SingletonLazyDCL() {} 
    public static SingletonLazyDCL getInstance() { 
        // 第一次检查,如果实例已存在,则直接返回,避免进入同步块,提高效率。 
        if (instance == null) { 
            // 加锁,确保只有一个线程能进入同步块 
            synchronized (SingletonLazyDCL.class) { 
                // 第二次检查,防止在等待锁的过程中,已有其他线程创建了实例。 
                if (instance == null) { 
                    instance = new SingletonLazyDCL(); 
                } 
            } 
        } 
        return instance; 
    } 
}

为什么用 volatile?
instance = new SingletonLazyDCL(); 这行代码不是一个原子操作,它分为三步:

  1. 分配内存空间
  2. 初始化对象
  3. 将 instance 指向分配的内存地址

如果没有 volatile,JVM 可能会进行指令重排序,导致步骤 3 在步骤 2 之前执行。这样另一个线程可能在第一次检查时看到 instance 不为 null(已经指向了内存地址),但对象还没有初始化完成,从而拿到一个不完整的对象。volatile 可以禁止这种重排序。

总结对比

特性饿汉式懒汉式(基础版)懒汉式(双重检查锁)
创建时机类加载时第一次调用 getInstance() 时第一次调用 getInstance() 时
线程安全是否是
资源利用差,可能浪费好好
性能获取实例快(线程不安全,无意义)第一次稍慢,之后快
实现难度简单简单复杂

在现代 Java 开发中,还有更简洁的实现单例的方式,比如使用 枚举(Enum),它天生就是单例的,并且能防止反射和反序列化攻击,是《Effective Java》作者强烈推荐的方式。

public enum SingletonEnum { 
    INSTANCE; 
    // 这就是单例的实例 
    public void doSomething() { 
        // ... 业务方法 
    } 
} 
// 使用:SingletonEnum.INSTANCE.doSomething();

目录

  1. 核心概念:单例模式
  2. 饿汉式
  3. 懒汉式
  4. 基础版(非线程安全)
  5. 改进版(线程安全,使用 synchronized)
  6. 最优版(双重检查锁 DCL)
  7. 总结对比
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • ModalAI VOXL2 与 ArduPilot 无 GPS 位置控制配置
  • 前端 AI 编码共享插件:Claude Code / Codex / OpenClaw 工作流实践
  • Spring Boot 消息队列与异步通信实战
  • openclaw新手入门指南:一文看懂环境搭建、模型配置与 WebUI 远程访问
  • Qlib 量化金融研究详细工作流指南
  • 前缀和算法:和为 k 的子数组与和可被 k 整除的子数组
  • 文心一言 4.5 开源测评与本地部署指南
  • 清华智谱开源 7440 亿参数智能体模型 GLM-5
  • 高校 AIGC 检测新规解读:AI 率标准与应对策略
  • SpringBoot 整合 Kafka 项目实战操作详解
  • 微信历史版本下载地址及关闭自动更新方法
  • LiquidBounce:基于 Fabric API 的 Minecraft 开源注入客户端
  • 深度学习与 AI 大模型技术指南
  • 基于 Xilinx FPGA 的 RISC-V 五级流水线 CPU 设计实战
  • Git Worktree 命令介绍与使用
  • FPGA 面试题汇总(一)
  • 算法进阶:一维前缀和原理与实战
  • QSDE:下一代 Python 异步下载引擎发布
  • ClawdBot (OpenClaw) 结合 Discord 机器人部署与配置指南
  • 数据结构初阶:树的概念、术语与表示方法

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online