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关键字内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

    MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

    本文给大家介绍MyBatis的xml中字符串类型判空与非字符串类型判空处理方式,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-08-08
  • Spring集成MyBatis框架

    Spring集成MyBatis框架

    本文主要介绍了Spring集成MyBatis的配置和使用,项目基于Maven构建,连接Mysql数据库。下面跟着小编一起来看下吧
    2017-02-02
  • @Cacheable 拼接key的操作

    @Cacheable 拼接key的操作

    这篇文章主要介绍了@Cacheable 拼接key的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • SpringBoot项目中如何实现MySQL读写分离详解

    SpringBoot项目中如何实现MySQL读写分离详解

    在高并发下需要对应用进行读写分离,配置多数据源,即写操作走主库,读操作则走从库,主从数据库负责各自的读和写,缓解了锁的争用,提高了读取性能,这篇文章主要给大家介绍了关于SpringBoot项目中如何实现MySQL读写分离的相关资料,需要的朋友可以参考下
    2022-07-07
  • RestTemplate对HttpClient的适配源码解读

    RestTemplate对HttpClient的适配源码解读

    这篇文章主要为大家介绍了RestTemplate对HttpClient的适配源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • 详解Java JDK动态代理

    详解Java JDK动态代理

    这篇文章主要介绍了Java JDK动态代理的相关资料,帮助大家更好的理解和学习Java 代理的有关知识,感兴趣的朋友可以了解下
    2020-08-08
  • Spring Cloud Eureka(全面解析) 大白话

    Spring Cloud Eureka(全面解析) 大白话

    这篇文章主要介绍了Spring Cloud Eureka(全面解析) 大白话,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java使用策略模式解决商场促销商品问题示例

    Java使用策略模式解决商场促销商品问题示例

    这篇文章主要介绍了Java使用策略模式解决商场促销商品问题,简单描述了策略模式的概念、原理,并结合实例形式分析了Java基于策略模式解决商品促销问题的相关操作技巧,需要的朋友可以参考下
    2018-05-05
  • 深入了解Springboot核心知识点之数据访问配置

    深入了解Springboot核心知识点之数据访问配置

    这篇文章主要为大家介绍了Springboot核心知识点中的数据访问配置,文中的示例代码讲解详细,对我们了解SpringBoot有一定帮助,快跟随小编一起学习一下吧
    2021-12-12
  • RocketMQ中消费者的消费进度管理

    RocketMQ中消费者的消费进度管理

    这篇文章主要介绍了RocketMQ中消费者的消费进度管理,业务实现消费回调的时候,当且仅当此回调函数返回ConsumeConcurrentlyStatus.CONSUME_SUCCESS ,RocketMQ才会认为这批消息(默认是1条)是消费完成的,需要的朋友可以参考下
    2023-10-10

最新评论