当前位置: 代码网 > it编程>编程语言>Java > java中volatile关键字解释说明

java中volatile关键字解释说明

2026年01月26日 Java 我要评论
在 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关键字内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com