0

0

如何在Java中实现类的单例模式_饿汉式与双重检查锁懒汉式写法

P粉602998670

P粉602998670

发布时间:2026-03-15 16:45:31

|

402人浏览过

|

来源于php中文网

原创

饿汉式单例在类加载时初始化,线程安全但不支持延迟加载;双重检查锁懒汉式支持延迟加载且线程安全,但必须用volatile防止重排序;枚举单例最可靠,由JVM保障安全性。

如何在java中实现类的单例模式_饿汉式与双重检查锁懒汉式写法

饿汉式单例:类加载时就初始化,简单但不支持延迟加载

饿汉式本质是靠 static 字段 + 私有构造 + 公共静态访问器实现的线程安全单例。JVM 类加载阶段就完成实例化,天然避免多线程竞争问题。

常见错误是把 INSTANCE 声明成非 final,导致后续被反射或序列化破坏单例性;或者忘了加 private 构造函数,外部仍可 new 实例。

  • INSTANCE 必须用 public static final 修饰,且初始化语句写在声明处(不能放到静态块里再赋值)
  • 构造函数必须是 private,否则无法阻止外部调用 new
  • 如果类依赖外部资源(比如数据库连接),饿汉式会在应用启动时就触发初始化,可能拖慢启动速度或引发早期失败

示例:

In3D
In3D

把真人变成化身,创建逼真且可自定义的虚拟角色

下载
public class EagerSingleton {
    public static final EagerSingleton INSTANCE = new EagerSingleton();
    private EagerSingleton() {}
}

双重检查锁懒汉式:延迟加载 + 线程安全,但 volatile 关键字不能少

懒汉式核心是“第一次调用 getInstance() 时才创建实例”,但直接加 synchronized 在方法上会严重拖慢性能。双重检查锁(DCL)是折中方案——外层判空不加锁,内层判空加锁,再加 volatile 防止指令重排序。

立即学习Java免费学习笔记(深入)”;

最常踩的坑就是漏掉 volatile。没有它,JVM 可能将对象引用赋值提前到构造函数执行完之前,导致其他线程拿到一个未初始化完成的对象,进而抛出 NullPointerException 或更隐蔽的状态异常。

  • instance 字段必须用 volatile 修饰,这是 DCL 正确性的前提
  • 两次 if (instance == null) 缺一不可:第一次减少锁开销,第二次防止多个线程同时通过第一层判断后重复创建
  • 锁对象必须是 Singleton.class 或当前类的静态 final 对象,不能用 this 或实例变量

示例:

public class DclSingleton {
    private static volatile DclSingleton instance;
    private DclSingleton() {}
    public static DclSingleton getInstance() {
        if (instance == null) {
            synchronized (DclSingleton.class) {
                if (instance == null) {
                    instance = new DclSingleton();
                }
            }
        }
        return instance;
    }
}

为什么不用枚举实现单例?它其实更可靠

枚举单例是 Effective Java 推荐的方式,由 JVM 保证线程安全、反序列化安全、反射攻击防护。它不是“写法技巧”,而是语言机制级保障。

很多人回避枚举,是因为误以为它“不够面向对象”或“不方便继承”。但单例本就不该被继承,且枚举可以定义方法、实现接口,功能并不受限。

  • 枚举实例天然 static final,无法通过反射调用私有构造(AccessibleObject.setAccessible(true) 对枚举构造无效)
  • 反序列化时,JVM 总是返回已有枚举实例,不会新建
  • 如果单例需要实现某个接口(如 Runnable),枚举可以直接 implements

示例:

public enum EnumSingleton {
    INSTANCE;
    public void doSomething() { /* ... */ }
}

单例测试和破坏场景:别只盯着写法,要验证是否真唯一

写完单例,不验证等于没写。尤其在多线程环境或涉及序列化/反射的场景下,看似正确的代码可能一跑就破。

容易被忽略的是:单元测试本身是单线程的,@Test 方法无法暴露 DCL 缺 volatile 的问题;而生产环境中的反射调用、反序列化、类加载器隔离等,都可能绕过你的保护逻辑。

  • Thread 启动 100+ 线程并发调用 getInstance(),断言所有返回引用相等(==
  • ObjectOutputStream / ObjectInputStream 序列化再反序列化,检查是否仍是同一实例
  • 用反射尝试调用私有构造函数,确认抛出 IllegalAccessException 或构造未被执行

复杂点在于:这些破坏手段在不同 JDK 版本、不同 JVM 参数(如开启 JIT 优化)下行为可能不同。越想“绝对安全”,越得在真实运行环境中验证,而不是只看代码长得像单例。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

254

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1131

2024.03.01

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

847

2023.08.22

go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

58

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

65

2025.11.27

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

76

2025.10.23

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1974

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

680

2025.10.17

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

69

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.4万人学习

Java 教程
Java 教程

共578课时 | 82.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号