Java多线程怎么保证可见性 Java内存模型JMM原理分析【源码】

大磊姑娘_5650

大磊姑娘_5650

2026-03-20

349人浏览

原创

volatile 解决多线程下变量修改不被立即可见的问题,通过强制主内存读写和插入内存屏障禁止重排序,但不保证复合操作原子性。

java多线程怎么保证可见性 java内存模型jmm原理分析【源码】

volatile 关键字到底解决了什么问题

Java 多线程中变量修改不被其他线程立即看到,根本原因不是“线程没刷新”,而是 JMM 允许每个线程拥有自己的工作内存(缓存),对 sharedVar 的读写可能只发生在本地副本上。用 volatile 修饰后,每次读都强制从主内存加载,每次写都立即刷回主内存,并插入内存屏障禁止重排序。

常见错误现象:while (!flag) { Thread.sleep(100); } 中 flag 被另一个线程设为 true,但当前线程永远不退出——因为 flag 没加 volatile,JIT 可能将其优化为常量判断或缓存到寄存器。

  • volatile 不能替代锁:它不保证复合操作的原子性(如 i++)
  • 适用于“一写多读”且无依赖关系的场景,比如状态标志、单次发布的对象引用
  • 在 JDK 1.5+ 后语义已严格基于 JMM 定义,旧版(如 1.4)行为不可靠

synchronized 和 final 怎么参与可见性保障

synchronized 块的进入和退出分别具有“读屏障”和“写屏障”效果:进入时清空本地工作内存,强制从主内存重新读取共享变量;退出时将本线程所有修改刷回主内存。这比 volatile 更重,但能同时解决原子性和可见性。

final 字段的可见性是编译期+运行期协同保证的:构造器内对 final 字段的写入,在构造完成前就对其他线程可见(前提是该对象未在构造过程中逸出)。这是通过禁止编译器/JIT 将 final 写操作重排序到构造器末尾之后实现的。

  • 不要在构造器里把 this 引用发布出去(如注册监听器、启动线程),否则 final 字段可能被看到默认值
  • synchronized(this) 和 synchronized(staticObj) 的可见性作用域不同:前者只同步实例变量,后者才影响静态变量
  • JDK 9+ 中 VarHandle 的 setRelease/getAcquire 提供了更细粒度的控制,语义接近 volatile 但可指定内存序

为什么 AtomicXXX 类能保证可见性却不显式用 volatile

以 AtomicInteger 为例,其内部 value 字段声明为 volatile:

private volatile int value;
所有原子方法(如 incrementAndGet())底层调用的是 Unsafe.compareAndSwapInt(),该指令本身具有内存屏障语义,且会触发 JVM 对 volatile 字段的读写协议。

容易忽略的点:AtomicInteger.get() 等读方法之所以可见,不是因为 CAS,而是因为字段本身是 volatile;而 lazySet()(即 setRelease)则只保证写入不重排序到之后,但不强制立即刷回主内存,适合性能敏感的“单向通知”场景。

  • 不要误以为 AtomicXXX 的所有方法都等价于加锁——weakCompareAndSet 在某些平台可能失败而不抛异常,也不提供强顺序保证
  • 若需对多个变量做原子更新,AtomicReferenceFieldUpdater 或 VarHandle 比锁更轻量,但要求字段必须是 volatile

JMM 源码里哪几行真正定义了 happens-before 规则

JMM 并没有一行“源码”直接定义 happens-before,它是规范层面的抽象模型。但在 OpenJDK 实现中,关键逻辑体现在:hotspot/src/share/vm/opto/graphKit.cpp 中的内存屏障插入策略、hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp 中对 membar 指令的生成、以及 hotspot/src/share/vm/runtime/synchronizer.cpp 中 monitor enter/exit 的内存语义处理。

真正影响开发者的是 Java 语言规范(JLS)第 17.4 节规定的 7 条 happens-before 规则,它们被编译器和 JVM 实现为具体屏障指令。比如“监视器锁规则”对应 synchronized 块退出时插入 StoreLoad 屏障,“volatile 变量规则”对应每次 volatile 写后插入 StoreStore + StoreLoad。

  • happens-before 是偏序关系,不是时间先后——A happens-before B,不代表 A 一定在 B 之前执行,只代表 A 的结果对 B 可见
  • JIT 编译器在满足 happens-before 前提下,仍可自由重排序指令,这是性能优化的基础,也是理解“看似乱序却不出错”的关键
  • 调试时用 -XX:+PrintAssembly 查看汇编,能看到 lock addl $0x0,(%rsp) 这类隐式内存屏障,就是 JVM 插入的
JMM 的复杂性不在语法,而在它把硬件内存模型、编译器优化、JVM 实现细节全揉进一套程序员可感知的语义里。最常被绕过的坑,是以为加了 volatile 就万事大吉,却忘了它不阻止指令重排对非 volatile 字段的影响。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

2023.10.24

5824

49

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.25

334

5

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

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

2025.10.23

674

12

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

3598

6

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

2025.12.24

1029

20

java多线程相关教程合集
java多线程相关教程合集

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

2026.01.21

343

30

C++多线程相关合集
C++多线程相关合集

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

2026.01.21

519

24

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

2026.02.06

349

20

C++多线程并发控制与线程安全设计实践
C++多线程并发控制与线程安全设计实践

本专题围绕 C++ 在高性能系统开发中的并发控制技术展开,系统讲解多线程编程模型与线程安全设计方法。内容包括互斥锁、读写锁、条件变量、原子操作以及线程池实现机制,同时结合实际案例分析并发竞争、死锁避免与性能优化策略。通过实践讲解,帮助开发者掌握构建稳定高效并发系统的关键技术。

2026.03.16

193

22

热门下载

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

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.3万人学习