0

0

如何在Java中使用volatile关键字_保证内存可见性与禁止指令重排序的原理

P粉602998670

P粉602998670

发布时间:2026-03-15 16:53:59

|

889人浏览过

|

来源于php中文网

原创

volatile不能保证原子性,因其仅确保可见性和禁止重排序,而i++等操作需“读-改-写”三步,多线程下仍可能交叉执行;适合纯状态标志位,复合操作须用AtomicInteger或锁。

如何在java中使用volatile关键字_保证内存可见性与禁止指令重排序的原理

volatile 为什么不能保证原子性

很多人以为加了 volatile 就能安全地做自增操作,结果还是出现数据错乱。根本原因是:可见性 ≠ 原子性。volatile 只保证每次读都从主内存取、每次写都立即刷回主内存,但 i++ 这种操作本身是“读-改-写”三步,在多线程下仍可能被交叉执行。

常见错误现象:counter 被多个线程反复 i++ 一万次,最终值却远小于预期;用 volatile 修饰 Boolean 标志位做开关,逻辑看似正确,但配合非原子操作(比如先判断再修改某个集合)时仍出问题。

  • 只适合纯状态标志位:如 runninginitialized,且后续操作不依赖该变量的旧值
  • 涉及复合操作(+=++、条件更新等),必须换 AtomicInteger 或加锁
  • volatile 对引用类型只保证引用本身的可见性,不保证其内部字段的可见性

volatile 如何禁止指令重排序

JVM 和 CPU 都可能对指令重排以提升性能,但 volatile 写操作会插入一个「StoreStore」屏障,读操作插入「LoadLoad」和「LoadStore」屏障,从而约束编译器和处理器的行为。

典型使用场景:双重检查锁(DCL)单例中,如果不加 volatile,可能导致对象被部分构造后就被其他线程看到——因为构造函数内的字段赋值可能被重排到对象引用赋值之后。

立即学习Java免费学习笔记(深入)”;

In3D
In3D

把真人变成化身,创建逼真且可自定义的虚拟角色

下载
  • 没有 volatile 的 DCL 中,instance = new Singleton() 可能被拆成:分配内存 → 设置引用 → 执行构造器;后两步顺序可能调换
  • 加上 volatile 后,JMM 强制要求:所有对该变量的写操作必须在引用发布前完成,且读线程能看到完整的初始化结果
  • 注意:这种重排序禁止仅对 volatile 变量本身及其前后的读写有约束,不是全局内存栅栏

volatile 在哪些场景下比 synchronized 更合适

当只需要“一个线程写、多个线程读”的简单通知语义,且无竞态逻辑时,volatile 开销远低于 synchronized —— 它不涉及锁获取/释放、线程挂起/唤醒,也不产生上下文切换。

常见误用:试图用 volatile 替代锁来保护一段临界区代码,或在循环中频繁读写 volatile 变量导致缓存行频繁失效(false sharing)。

  • 推荐场景:状态开关(shutdownRequested)、初始化完成标志(isReady)、轻量级信号量(配合 Thread.yield() 等轮询)
  • 慎用场景:高频率读写(如计数器)、需要与其他变量保持一致性的组合状态(如 volatile int countArrayList items 配合使用)
  • 性能影响:现代 JVM 对 volatile 读做了优化(基本等同普通读),但写操作仍需内存屏障,比普通写慢约 10–20%;在多核密集写场景下,还会加剧缓存一致性协议开销

volatile 与 happens-before 关系的实操理解

volatile 是 Java 内存模型(JMM)中定义的 happens-before 规则之一:对一个 volatile 变量的写操作,happens-before 于任意后续对该变量的读操作。这是它实现可见性和有序性的理论基础。

容易忽略的关键点:这个规则只对“同一个 volatile 变量”成立;如果线程 A 写了 volatile flag = true,然后修改了普通变量 data = 42,线程 B 读到 flag == true,并不能保证看到 data == 42 —— 除非 data 也声明为 volatile,或用锁同步。

  • 要让非 volatile 变量的修改对读线程可见,必须把它们放在同一个同步措施下:要么全用 volatile,要么进同一把锁,要么用 AtomicReferenceFieldUpdater 等工具类
  • 编译器不会对 volatile 操作做重排序优化,但会对它周围的普通变量重排——所以别指望靠它“顺便”保护邻近字段
  • 调试时看不到重排序效果,因为它是运行时现象,且依赖具体硬件和 JVM 实现;验证必须靠并发压力测试 + 字节码/汇编分析
事情说清了就结束。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

367

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

42

2025.11.30

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

203

2023.11.20

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1051

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

616

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

335

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

235

2025.08.29

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

76

2025.10.23

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

69

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.4万人学习

Java 教程
Java 教程

共578课时 | 82.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号