理解 JVM 的 8 个原子操作与 `volatile` 的语义

理解 JVM 的 8 个原子操作与 volatile 的语义

在并发编程中,volatile 常常被提及。但要真正理解它的作用,需要先回到 Java 内存模型(JMM) 的基础:线程与主内存之间的交互。JMM 定义了 8 个原子操作 来描述这些交互过程,而 volatile 的语义正是基于它们实现的。


JVM 的 8 个原子操作

JMM 把 主内存工作内存执行引擎 的数据交互拆分成了 8 个最小操作,这些操作是并发语义的基石:

  1. lock(锁定)

    将主内存中的变量标记为某个线程独占。

  2. unlock(解锁)

    解除独占标记,使变量可被其他线程访问。

  3. read(读取)

    从主内存中读取变量值,传输到线程的通道。

  4. load(载入)

    read 到的值写入线程工作内存的变量副本。

  5. use(使用)

    将工作内存中的值传给执行引擎使用。

  6. assign(赋值)

    将执行引擎计算后的值赋给工作内存中的变量副本。

  7. store(存储)

    将工作内存的值传输到通道。

  8. write(写入)

    store 传来的值写入主内存。


四组配对关系

这 8 个操作其实是 四组成对动作

  • lock / unlock:保证变量在某一时刻只有一个线程独占。
  • read / load:把主内存的值带入工作内存。
  • store / write:把工作内存的值写回主内存。
  • use / assign:工作内存与执行引擎之间的数据交互。

示意图:

主内存 <──read/load──> 工作内存 <──use/assign──> 执行引擎

^ │

└─────────────store/write───────────┘

其中 use/assign 仅在 线程内部 发生,对跨线程的可见性影响不大,因此开发者平时不太关心它。


volatile 的语义

volatile 并不会改变 8 个原子操作的存在方式,而是通过 内存屏障 来影响其中部分操作的执行顺序和可见性:

  1. 保证可见性

    • 写入 volatile 变量:强制执行 store → write,立即刷新主内存。
    • 读取 volatile 变量:强制执行 read → load,直接从主内存取值。
  2. 保证有序性

    • volatile 写操作前后,JVM 插入 StoreStore、StoreLoad 屏障,防止指令重排。
    • volatile 读操作后,插入 LoadLoad、LoadStore 屏障,确保读到的值对后续操作可见。
  3. 不保证原子性

    • volatile 只能保证单次读/写的原子性。
    • 对于复合操作(如 count++),依然会分解成多步(read → load → use → assign → store → write),在多线程下可能出现 丢失更新

为什么 use / assign 看似多余?

有人会觉得 use/assign 没有必要,因为我们写代码时从未直接操作过它。实际上:

  • read/load、store/write 关注的是 线程与主内存之间 的数据交换。
  • use/assign 关注的是 线程工作内存与执行引擎之间 的交互。

这部分虽然我们平时感知不到,但在 JMM 的规范 层面,它是必须被定义的,否则无法保证指令级别的精确定义。


总结

  • JVM 的 8 个原子操作分别是:lock / unlock / read / load / use / assign / store / write
  • 它们可以配对为四组:
    • lock/unlock
    • read/load
    • store/write
    • use/assign
  • volatile 主要约束的是 read+load、store+write ,配合内存屏障保证 可见性 + 有序性
  • volatile 不保证复合操作的原子性 ,如果需要保证,需要 CAS

✍️ 记住一句话:
volatile 让读写操作直达主内存,并通过内存屏障保证顺序,但不会把复合操作变成原子操作。

相关推荐
Ray Liang18 分钟前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Java水解33 分钟前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
SimonKing5 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean5 小时前
Jackson View Extension Spring Boot Starter
java·后端
Seven976 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
皮皮林55115 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河16 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
桦说编程18 小时前
从 ForkJoinPool 的 Compensate 看并发框架的线程补偿思想
java·后端·源码阅读
躺平大鹅20 小时前
Java面向对象入门(类与对象,新手秒懂)
java