java中volatile关键字解释说明

 更新时间:2026年01月26日 11:22:41   作者:菜鸡上道  
volatile是Java中的一个关键字,用于修饰变量,保证其可见性和禁止指令重排序,但不保证原子性,下面我们从原理层面详细解析volatile 的工作机制,感兴趣的朋友跟随小编一起看看吧

在 Java 中,volatile 是一个轻量级的同步机制关键字,用于修饰字段(变量),其核心作用是:

保证变量的“可见性”和“禁止指令重排序”,但不保证原子性。

下面我们从原理层面详细解析 volatile 的工作机制。

一、三大特性:可见性、有序性、原子性

特性volatile 是否支持说明
可见性(Visibility)✅ 支持一个线程修改了 volatile 变量,其他线程能立即看到最新值
有序性(Ordering)✅ 支持(禁止重排序)JVM 和 CPU 不会对 volatile 读写进行重排序优化
原子性(Atomicity)❌ 不支持(除 long/double 的简单读写)i++ 这类复合操作不是原子的

二、volatile 的底层原理(基于内存模型)

1.Java 内存模型(JMM)背景

  • 每个线程有自己的工作内存(缓存、寄存器)
  • 所有变量存储在主内存
  • 线程对变量的操作必须先从主内存拷贝到工作内存,操作后再写回

问题:如果没有同步机制,线程 A 修改了变量,线程 B 可能永远看不到新值(因为读的是本地缓存)。

2.volatile 如何解决可见性?

当一个字段被声明为 volatile

  • 写操作:线程必须将该变量的最新值立即刷新到主内存
  • 读操作:线程必须从主内存重新读取该变量的值,而不是使用本地缓存

这相当于每次读写都强制与主内存同步。

3.内存屏障(Memory Barrier / Memory Fence)

JVM 在编译 volatile 读写时,会插入内存屏障指令,实现两个效果:

(1)禁止指令重排序

  • 在 volatile 写之前的操作,不能重排到写之后
  • 在 volatile 读之后的操作,不能重排到读之前

例如:

// 假设 flag 是 volatile
a = 1;          // 普通写
flag = true;    // volatile 写

a = 1 一定发生在 flag = true 之前,不会被重排序。

(2)强制刷新缓存

  • 写屏障(Store Barrier):确保写入主内存
  • 读屏障(Load Barrier):确保从主内存加载

这些屏障由 JVM 根据不同 CPU 架构(x86、ARM 等)生成对应的底层指令(如 lock 前缀指令)。

三、典型应用场景

✅ 场景 1:状态标志位(最常见)

public class TaskRunner {
    private volatile boolean running = true;
    public void stop() {
        running = false; // 其他线程能立即看到
    }
    public void run() {
        while (running) {
            // do work
        }
    }
}

若不用 volatilerun() 方法可能因读取本地缓存而永远无法退出。

✅ 场景 2:单例模式中的双重检查锁定(DCL)

public class Singleton {
    private static volatile Singleton instance;
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton(); // 防止重排序导致未初始化完成就被引用
                }
            }
        }
        return instance;
    }
}

如果没有 volatilenew Singleton() 的三步(分配内存、初始化、赋值)可能被重排序为“分配 → 赋值 → 初始化”,导致其他线程拿到未初始化的对象。

❌ 不适用场景:复合操作(非原子)

private volatile int count = 0;
public void increment() {
    count++; // 实际是:读取 count → +1 → 写回,非原子!
}

此时应使用 AtomicInteger 或加锁。

四、与 synchronized 的区别

特性volatilesynchronized
保证可见性
保证原子性❌(除简单读写)
保证有序性✅(禁止重排序)✅(隐式包含)
性能开销低(无锁)较高(涉及 Monitor 锁)
适用范围仅变量方法/代码块/变量

volatilesynchronized 的轻量替代方案,但功能更弱。

五、补充:long 和 double 的特殊性

Java 规范规定:

  • 非 volatile 的 long/double,读写可能被拆分为两个 32 位操作(非原子)
  • volatile 的 long/double,JVM 保证读写是原子的(64 位一次性操作)

总结

volatile 的核心原理是:

  1. 通过内存屏障实现变量的可见性
  2. 禁止编译器和处理器重排序,保证有序性
  3. 不提供原子性,不能用于复合操作。

适用条件

当一个变量被多个线程访问,且满足:

  • 写操作不依赖当前值(如 flag = true
  • 或者只有一个线程写,其他线程只读

否则,请使用 synchronizedReentrantLockjava.util.concurrent.atomic 包中的原子类。

如需进一步了解内存屏障或 JMM 模型,也可以继续提问!

到此这篇关于java中volatile关键字解释说明的文章就介绍到这了,更多相关java volatile关键字内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java之单链表问题解决案例讲解

    Java之单链表问题解决案例讲解

    这篇文章主要介绍了Java之单链表问题解决案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Springboot之@ConfigurationProperties注解解读

    Springboot之@ConfigurationProperties注解解读

    在Spring Boot中,@EnableConfigurationProperties注解的主要作用是激活@ConfigurationProperties注解的配置属性类,从而让配置属性类能被Spring容器管理,这样的话,我们就可以在属性类中轻松地使用@ConfigurationProperties来绑定配置文件中的属性
    2024-10-10
  • Java的Semaphore信号量使用及原理解读

    Java的Semaphore信号量使用及原理解读

    这篇文章主要介绍了Java的Semaphore信号量使用及原理解读,Semaphore(信号量)是Java中一个并发控制工具,用于控制对共享资源的访问,它基于计数器的原理,可以限制同时访问某个资源的线程数量,需要的朋友可以参考下
    2023-12-12
  • Spring IOC源码之bean的注册过程讲解

    Spring IOC源码之bean的注册过程讲解

    这篇文章主要介绍了Spring IOC源码之bean的注册过程讲解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • 小白教程! Linux服务器上JDK安装配置方法

    小白教程! Linux服务器上JDK安装配置方法

    这篇文章主要为大家详细介绍了Linux服务器上JDK安装配置方法,小白教程!具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • HttpClient连接池及重试机制解析

    HttpClient连接池及重试机制解析

    这篇文章主要介绍了HttpClient连接池及重试机制解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • SpringBoot中配置属性热更新的轻量级实现方案

    SpringBoot中配置属性热更新的轻量级实现方案

    项目开发中,每次修改配置都要重启服务,不仅开发效率低,线上重启还会导致短暂不可用,今天分享一个轻量级方案,基于SpringBoot原生能力实现配置热更新,有需要的可以了解下
    2025-07-07
  • java爬虫Gecco工具抓取新闻实例

    java爬虫Gecco工具抓取新闻实例

    本篇文章主要介绍了JAVA 爬虫Gecco工具抓取新闻实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-10-10
  • Mybatis-Plus实现SQL拦截器的示例

    Mybatis-Plus实现SQL拦截器的示例

    这篇文章主要介绍了Mybatis-Plus实现一个SQL拦截器,通过使用SQL拦截器,开发人员可以在执行SQL语句之前或之后对其进行修改或记录,从而更好地控制和优化数据库操作,对Mybatis-Plus SQL拦截器相关知识感兴趣的朋友一起看看吧
    2023-05-05
  • Java中实现String.padLeft和String.padRight的示例

    Java中实现String.padLeft和String.padRight的示例

    本篇文章主要介绍了Java中实现String.padLeft和String.padRight,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09

最新评论