news 2026/4/23 9:49:34

懒加载单例模式中DCL方式和原理解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
懒加载单例模式中DCL方式和原理解析

一、DCL 是什么?

DCL(Double Check Lock,双重检查锁)是 Java 中懒加载单例模式的高性能实现方案,核心思路是:

  • 第一次检查:无锁判断实例是否已初始化,避免每次调用都加锁(提升性能);
  • 加锁:保证多线程下只有一个线程能进入初始化逻辑;
  • 第二次检查:防止多个线程等待锁后重复初始化实例。

它解决了传统 “懒汉式(同步方法)” 每次调用都加锁的性能问题,同时保证线程安全。

二、DCL 完整实现代码(标准写法)

public class SingletonDCL { // 1. 必须加 volatile 关键字! private static volatile SingletonDCL INSTANCE; // 2. 私有构造器,禁止外部实例化 private SingletonDCL() {} // 3. 双重检查锁的核心方法 public static SingletonDCL getInstance() { // 第一次检查:无锁,快速判断实例是否已存在 // 若已存在,直接返回,无需加锁,提升高并发性能 if (INSTANCE == null) { // 加锁:保证同一时间只有一个线程能进入初始化逻辑 synchronized (SingletonDCL.class) { // 第二次检查:防止多个线程等待锁后重复创建实例 if (INSTANCE == null) { // 初始化实例 INSTANCE = new SingletonDCL(); } } } return INSTANCE; } }

三、DCL 核心逻辑拆解(为什么要 “双重检查”)

假设高并发场景下有 3 个线程(T1、T2、T3)同时调用getInstance()

  1. T1 先执行:第一次检查INSTANCE == null为 true,进入加锁逻辑,第二次检查仍为 true,执行INSTANCE = new SingletonDCL(),初始化完成后释放锁;
  2. T2 随后执行:第一次检查INSTANCE已不为 null,直接返回实例,无需加锁;
  3. T3 与 T1 同时执行:T3 先通过第一次检查(此时 T1 还未完成初始化),等待 T1 释放锁后进入加锁逻辑,第二次检查发现INSTANCE已被 T1 初始化,直接返回,避免重复创建。

如果去掉 “第二次检查”,T3 会在 T1 释放锁后重新创建实例,导致单例失效。

四、为什么必须加volatile?(面试必考)

这是 DCL 最核心的坑点!INSTANCE = new SingletonDCL()看似一行代码,实际 JVM 会拆分为 3 步执行:

1. 分配内存空间(给 SingletonDCL 实例); 2. 初始化实例(执行构造器逻辑,给成员变量赋值); 3. 将 INSTANCE 引用指向分配的内存空间(此时 INSTANCE 不再为 null)。

JVM 为了优化性能,可能会对这 3 步进行指令重排(比如重排为 1→3→2),导致问题:

  • T1 执行时,JVM 先执行 1→3(INSTANCE 不为 null,但实例还未初始化);
  • T2 此时第一次检查INSTANCE != null,直接返回这个 “半初始化” 的实例;
  • T2 调用实例的方法时,会因实例未初始化完成抛出空指针或逻辑错误。

volatile关键字的核心作用:禁止 JVM 对指令重排,保证 1→2→3 的执行顺序,确保其他线程看到的INSTANCE要么是 null,要么是完全初始化的实例。

五、DCL 的常见误区(避坑)

错误写法问题说明
去掉volatile可能拿到 “半初始化” 实例,线程安全失效
去掉第二次检查多线程等待锁后重复创建实例,单例失效
同步代码块锁对象错误(比如锁thisstatic方法中this不存在,且锁对象不唯一,线程安全失效
INSTANCE定义为finalfinal变量必须初始化,无法实现懒加载

六、DCL 的优缺点

优点缺点

1. 懒加载:实例仅在第一次调用时初始化,节省内存;

2. 高性能:仅初始化时加锁,后续调用无锁;

3. 线程安全:双重检查 + volatile 保证单例唯一性

1. 实现稍复杂,新手易遗漏 volatile;

2. 无法解决 “反射 / 序列化破坏单例” 的问题(需额外处理);

3. 在早期 JDK(1.4 及之前)中,volatile 实现有缺陷,DCL 可能失效(现代 JDK 已修复)

七、DCL 的适用场景

  • 高并发场景下的懒加载单例(比如工具类、连接池、配置中心实例);
  • 对内存占用敏感,需要延迟初始化的场景;
  • 追求高性能,不希望每次调用都加锁的场景。

总结

  1. DCL 是 “懒加载 + 高性能 + 线程安全” 的单例实现方案,核心是 “两次检查 + 加锁 + volatile”;
  2. volatile是 DCL 的关键,用于禁止指令重排,避免拿到半初始化实例;
  3. 第二次检查不可省略,否则多线程下会重复创建实例;
  4. 现代 JDK(1.5+)中 DCL 是安全的,是生产环境中最常用的单例实现方式之一。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 9:48:47

提供一下获取的NTP时间中的月和周的枚举

你这个 CIPSNTPTIME 返回的时间字符串格式本质上就是 ctime() 风格(例如:Wed Feb 4 10:14:03 2026),其中:周:固定是 3 字母英文缩写月:固定是 3 字母英文缩写下面把“周 / 月”的枚举&#xff0…

作者头像 李华
网站建设 2026/4/23 9:49:25

Undertow不支持大文件上传,使用application.yml配置失效

这是一个 Spring Boot 配置类,用于自定义 Undertow Web 服务器的配置,主要目的是调整请求体(包括文件上传)的最大大小限制。 一、类结构说明 1. Configuration 表明这是一个 Spring 配置类,会在应用启动时被加载。用…

作者头像 李华
网站建设 2026/4/23 9:47:16

基于springboot的健身服务与轻食间平台管理系统设计实现

背景分析 现代生活节奏加快,健康管理需求显著增长。健身与饮食作为健康管理的两大核心要素,传统服务模式存在信息割裂、效率低下等问题。健身机构与轻食商家缺乏数字化协同平台,用户难以获得科学的一体化健康解决方案。 行业痛点 健身行业…

作者头像 李华
网站建设 2026/4/23 9:48:00

如何做谷歌seo搜索优化?实战派老鸟的干货分享

很多人觉得做谷歌排名是一件特别玄学的事情,苦苦追寻那些复杂的算法更新看看,最后反而把自己搞糊涂了。其实回归本质,谷歌就是一个给用户找答案的工具。你想排在前面,就得证明你的答案比别人的更靠谱、更专业。今天大家不聊那些虚…

作者头像 李华
网站建设 2026/4/23 9:51:06

Tomcat的概念

Tomcat(全称 Apache Tomcat)是一个开源的、轻量级的Web应用服务器和Servlet容器,由Apache软件基金会开发和维护。它主要用于部署和运行基于Java的Web应用程序,特别是遵循Java Servlet、JavaServer Pages(JSP&#xff0…

作者头像 李华
网站建设 2026/4/23 16:12:10

48节点配电系统仿真:Matlab/Simulink的实战应用

48节点 配电系统仿真 Matlab/simulink质量过硬,非诚勿扰! 该模型依据实际配电网(含单相供电)搭建,电压等级10kV/380V,频率50Hz,贴近我国电网实际。 可用于: 1、研究SVG配电系统对节点电压的影响&#xff1…

作者头像 李华