监视器锁和volatile变量均通过happens-before关系建立可见性保证:锁规则要求同一锁的解锁happens-before后续加锁,volatile规则要求写happens-before后续读,二者都强制刷写主存与重载最新值,但锁还保障原子性而volatile不保障。

理解监视器锁规则和 volatile 变量规则,关键在于抓住它们共同的目标:**建立操作之间的可见性保证**,而不是描述物理时间先后。两者都通过 JMM(Java 内存模型)的 happens-before 关系,让一个线程的写入对另一个线程可读。
监视器锁规则:解锁与加锁构成“接力”
规则表述:对同一个锁的解锁操作 happens-before 后续对该锁的加锁操作。
这意味着:线程 A 在 synchronized 块中修改了共享变量并退出(自动解锁),线程 B 随后进入同一个锁的 synchronized 块(加锁),那么 A 的所有写操作结果,对 B 来说一定可见。
- 依赖“同一个锁”——换一个锁对象,这条规则不成立
- 解锁时,JMM 强制把该线程工作内存中被锁保护的变量刷回主内存
- 加锁时,JMM 强制让该线程工作内存中对应变量的副本失效,后续必须从主内存重新读取
- 它不仅保障可见性,还天然排除了临界区的并发执行,因此也保障原子性
volatile 变量规则:读写之间建立单向通道
规则表述:对一个 volatile 变量的写操作 happens-before 后续任意线程对该变量的读操作。
立即学习“Java免费学习笔记(深入)”;
这意味着:只要线程 A 写了 volatile flag = true,之后线程 B 读到 flag == true,那么 B 就一定能看见 A 在写 flag 之前 所做的所有操作(比如给普通变量 data 赋值)。
- volatile 写相当于插入一个store-load 内存屏障,禁止指令重排序,并强制刷新到主内存
- volatile 读相当于插入一个load-load + load-store 内存屏障,禁止重排序,并强制从主内存加载最新值
- 它只保障可见性和有序性(禁止特定重排),不保障原子性(如 i++ 仍非原子)
- 不需要锁对象,开销比 synchronized 小,适合状态标志、一次性发布等场景
两者的本质联系与区别
锁释放与 volatile 写具有相同的内存语义:都把本地修改写入主内存;锁获取与 volatile 读具有相同的内存语义:都丢弃本地缓存、强制读主内存。但锁是粗粒度、可重入、支持阻塞的同步机制;volatile 是细粒度、无锁、仅适用于简单状态通知的可见性工具。


















