volatile 的作用

在上篇博客中,已经提到 volatile 保证内存可见性的作用,这次加上 volatile 禁止指令重排序的作用。

java 复制代码
class SingletonLazy {
    private static volatile SingletonLazy instance = null;
    
    public static  SingletonLazy getInstance() {
        if(instance == null) {
            synchronized (SingletonLazy.class) {
                if(instance == null) {
                    instance = new SingletonLazy();
                }
            }
        }
        return instance;
    }
    
    private SingletonLazy() {
        
    }
}

如果没有 volatile,这段代码在多线程环境下可能返回一个"未完全初始化"的对象,导致严重 bug!

🔍 为什么需要它?------ 深入分析"对象创建"过程

new SingletonLazy() 看似一行代码,但在 JVM 底层其实分为 3 步:

  1. 分配内存空间(为 SingletonLazy 对象分配堆内存)

  2. 调用构造方法(初始化对象的字段、执行构造逻辑)

  3. 将引用赋值给 instanceinstance = 引用地址

⚠️ 问题:JVM 可能重排序!

在没有 volatile 的情况下,JVM 或 CPU 可能将步骤 2 和 3 重排序,变成:

  1. 分配内存

  2. 将引用赋值给 instance(此时对象尚未初始化!)

  3. 调用构造方法(延迟执行)

💥 这就是 "指令重排序"(Instruction Reordering) 优化。

🧨 多线程下的灾难场景(无 volatile

假设有两个线程 T1 和 T2:

时间 T1(正在创建实例) T2(调用 getInstance()
1 执行 new: ① 分配内存 ③ 先赋值 instance = 地址(重排序!) ---
2 --- 检查 if (instance == null)false!(因为 instance 已非 null)
3 --- 直接 return instance(拿到一个未初始化的对象!)
4 ② 执行构造方法(太晚了!) 使用 instance访问未初始化的字段 → NullPointerException / 数据错误!

❌ 这就是著名的 "DCL 失效问题"(在 Java 5 之前无法安全修复)。

volatile 如何解决这个问题?

当你声明:

java 复制代码
private static volatile SingletonLazy instance = null;

volatile 提供两个关键保障:

  1. 禁止重排序
  • JVM 保证 instance = new SingletonLazy() 的三步操作不会被重排序。

  • 必须严格按照:分配内存 → 初始化 → 赋值 的顺序执行。

  1. 保证可见性
  • 当 T1 执行 instance = ... 后,T2 立即能看到最新值(不会读到缓存中的 null)。

✅ 结果:T2 要么看到 instance == null(继续等待锁),

要么看到一个完全初始化好的对象。

❌ 如果去掉 volatile 会怎样?

java 复制代码
private static SingletonLazy instance = null; // 没有 volatile!
  • 单线程:一切正常。

  • 多线程:有极小概率(但确实存在)返回未初始化对象。

  • Bug 难以复现(依赖 CPU/JVM/时机),但一旦发生,后果严重(崩溃、数据错乱)。

🐞 这类 bug 被称为 "Heisenbug"(观测时消失,不观测时出现)。

相关推荐
JH30732 小时前
SpringBoot 优雅处理金额格式化:拦截器+自定义注解方案
java·spring boot·spring
Coder_Boy_3 小时前
技术让开发更轻松的底层矛盾
java·大数据·数据库·人工智能·深度学习
helloworldandy3 小时前
使用Pandas进行数据分析:从数据清洗到可视化
jvm·数据库·python
invicinble3 小时前
对tomcat的提供的功能与底层拓扑结构与实现机制的理解
java·tomcat
较真的菜鸟4 小时前
使用ASM和agent监控属性变化
java
黎雁·泠崖4 小时前
【魔法森林冒险】5/14 Allen类(三):任务进度与状态管理
java·开发语言
qq_12498707535 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_5 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
Mr_sun.5 小时前
Day06——权限认证-项目集成
java
瑶山5 小时前
Spring Cloud微服务搭建四、集成RocketMQ消息队列
java·spring cloud·微服务·rocketmq·dashboard