news 2026/6/10 21:06:24

Java 使用 volatile + 双重检查锁(DCL)实现单例模式的最佳方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 使用 volatile + 双重检查锁(DCL)实现单例模式的最佳方案

为什么要这么做?因为在并发场景下,双重检查锁(DCL)确实存在严重问题——

问题的核心根源

指令重排序

helper=newHelper();// 这不是原子操作

实际上包含三个步骤:

  1. Helper对象分配内存空间
  2. 调用构造函数初始化对象
  3. 将引用赋值给helper变量

问题在于:步骤2和步骤3可能被JVM重排序,导致另一个线程看到一个未完全初始化的对象

具体场景分析

// 线程1执行helper=newHelper();// 重排序后:分配内存 → 赋值引用 → 初始化// 在线程1赋值引用后、初始化前,线程2进入if(helper==null){// helper不为null,但对象未初始化!// 跳过同步块returnhelper;// 返回一个半成品对象!}

JDK5+的推荐解决方案

使用volatile关键字

classSingleton{privatevolatileHelperhelper=null;// 关键:添加 volatilepublicHelpergetHelper(){if(helper==null){// 第一次检查(无锁)synchronized(this){// 加锁if(helper==null){// 第二次检查(有锁)helper=newHelper();// 安全初始化}}}returnhelper;}}

volatile如何解决问题

1.禁止指令重排序

  • volatile写之前的所有操作,都不会被重排序到写之后
  • volatile读之后的所有操作,都不会被重排序到读之前
  • 具体来说:helper = new Helper()的初始化操作(构造函数调用)会在赋值之前完成

2.保证内存可见性

  • 当一个线程修改volatile变量时,新值会立即被刷新到主内存
  • 其他线程读取volatile变量时,会从主内存重新加载最新值

3.建立 happens-before 关系

根据JSR-133(Java内存模型增强)

  • volatile变量的写操作 happens-before 于后续对该变量的读操作
  • 这保证了所有线程看到的初始化状态是一致的

完整的线程安全示例

publicclassSafeDoubleCheckedLocking{// 必须使用 volatile 修饰privatevolatileResourceresource;publicResourcegetResource(){// 第一次检查:大多数情况不需要同步,提升性能Resourceresult=resource;if(result==null){// 同步块:确保只有一个线程初始化synchronized(this){result=resource;if(result==null){// volatile 保证初始化完成前不会发布引用resource=result=newResource();}}}returnresult;}staticclassResource{// 资源类的定义publicResource(){// 复杂的初始化逻辑}}}

为什么这个方案适用于JDK5+

Java内存模型的演进

  • JDK 1.4及之前:DCL根本无法正确实现,volatile语义不完整
  • JDK 5(JSR-133):重新定义了内存模型,强化了volatile的语义
    • 禁止特定类型的指令重排序
    • 建立了更强的 happens-before 关系
    • 修复了DCL的根本问题

替代方案比较

方案优点缺点
volatile + DCL性能好(大多数情况无锁)代码稍复杂,需要JDK5+
静态内部类简洁安全,延迟加载无法传参初始化
枚举单例绝对安全,防止反射攻击不够灵活
synchronized方法简单安全每次访问都同步,性能差

最佳实践建议

  1. 优先考虑其他单例模式

    • 静态内部类(如果不需要传参)
    • 枚举单例(如果需要绝对安全)
  2. 必须使用DCL时

    // 确保:// 1. 使用 volatile// 2. 使用JDK5+// 3. 两次检查都不省略
  3. 性能考量

    • DCL在初始化后几乎没有性能损耗
    • 适合初始化成本高、频繁访问的场景
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 12:27:05

适配多种任务类型:lora-scripts对LLaMA 2、ChatGLM等LLM的支持

适配多种任务类型:lora-scripts对LLaMA 2、ChatGLM等LLM的支持 在大模型时代,一个现实问题始终困扰着开发者:如何用有限的算力资源,让通用语言模型真正“懂”某个专业领域?比如,你手握一个70亿参数的LLaMA …

作者头像 李华
网站建设 2026/6/10 12:34:11

消费级显卡也能跑!lora-scripts支持RTX3090/4090低资源训练LoRA

消费级显卡也能跑!lora-scripts支持RTX3090/4090低资源训练LoRA 在生成式AI席卷创意与产业的今天,一个曾经遥不可及的梦想正变得触手可及:普通人用一张家用显卡,也能训练出属于自己的专属AI模型。这不再是实验室里的专利&#xff…

作者头像 李华
网站建设 2026/6/10 14:35:15

仓库货物智能检测:从YOLOv11模型训练到UI界面开发,一站式搞定仓储自动化检测方案

文章目录 仓库货物智能检测:从YOLOv11模型训练到UI界面开发,一站式搞定仓储自动化检测方案 一、项目背景:为什么要做仓库货物智能检测? 二、核心技术:YOLOv11为何是仓储检测的优选? (1)YOLOv11的核心优势 三、数据集准备:让模型“见多识广”的关键一步 (1)数据集选择…

作者头像 李华
网站建设 2026/6/10 14:58:03

电影字幕自动生成系统:基于YOLOv11的智能字幕识别与生成全流程指南

文章目录 电影字幕自动生成系统:基于YOLOv11的智能字幕识别与生成全流程指南 引读:让电影字幕识别准确率超93%的高效方案 一、项目背景与技术价值 二、环境搭建:从依赖安装到代码准备 1. 必备依赖安装 2. 代码仓库与版本确认 三、数据准备:让模型“识别”电影字幕 1. 数据集…

作者头像 李华
网站建设 2026/6/10 14:36:51

提示词调用语法详解:ora:my_style_lora:0.8背后的机制

提示词调用语法详解:ora:my_style_lora:0.8背后的机制 在当前AI生成内容爆发的时代,我们早已不再满足于“画得像”或“写得通顺”的通用模型输出。无论是设计师想复现独特的插画风格,还是企业需要定制专属品牌语调的对话机器人,个…

作者头像 李华
网站建设 2026/6/10 3:12:19

conda环境创建指令汇总:确保依赖隔离与稳定

Conda环境构建实战:为LoRA训练打造稳定、可复现的AI开发底座 在如今快速迭代的AI研发环境中,一个常见的尴尬场景是:某个LoRA微调脚本在同事的机器上跑得飞起,换到自己电脑却报出一连串“ModuleNotFoundError”或CUDA版本不兼容的错…

作者头像 李华