锁释放与获取通过建立happens-before关系解决可见性与有序性问题:获取锁时强制读主内存最新值,释放锁时强制写回主内存,配对使用即可实现线程间通信,底层依赖volatile和cas保证语义。

锁释放与锁获取的内存语义,核心是解决多线程环境下共享变量的**可见性**和**有序性**问题。它不是单纯保证互斥,更关键的是建立线程间通信机制——让一个线程的修改对另一个线程“及时可见”。
锁获取:强制从主内存读取最新值
当线程成功获取锁(比如进入 synchronized 块或调用 ReentrantLock.lock()),JMM 会把该线程本地内存中所有共享变量的副本标记为无效。后续对该变量的任何读取,都必须重新从主内存加载。
- 效果等同于 volatile 读:确保看到之前其他线程写入的最新结果
- 不依赖变量是否声明为 volatile —— 锁本身就能提供这种保障
- 即使变量是普通 int、boolean,只要被同一把锁保护,读操作就具备“读最新值”的语义
锁释放:强制把变更刷回主内存
当线程释放锁(退出 synchronized 块或调用 unlock()),JMM 会把该线程本地内存中所有被修改过的共享变量,全部写回到主内存。
- 效果等同于 volatile 写:确保自己的修改对后续获取同一把锁的线程可见
- 刷新动作发生在 unlock 的那一刻,不是每次赋值都刷,而是批量、延迟但确定地同步
- 这避免了因 CPU 缓存或编译器重排序导致的“写丢失”或“读旧值”
锁释放 → 锁获取:构成线程间消息传递
如果线程 A 释放锁后,线程 B 随后获取同一把锁,JMM 就在这两个动作之间建立了 happens-before 关系。这意味着:
- A 在释放锁前对共享变量的所有写操作,对 B 获取锁后的读操作一定可见
- 这个过程本质上是 A 通过主内存向 B 发送了一条“我改完了”的隐式消息
- 不需要额外加 volatile 或 synchronized 嵌套,单靠锁的配对使用即可保证跨线程数据传递
底层实现靠的是 volatile + CAS
以 ReentrantLock 为例,其 state 字段被声明为 volatile,lock() 中的 compareAndSetState() 调用既是原子操作,又天然具备 volatile 读/写的内存语义:
- 获取锁时的 CAS 操作包含 volatile 读(读 state)
- 释放锁时对 state 的写(如设为 0)是 volatile 写
- 正是这些底层 volatile 语义,支撑起了上层锁的内存可见性保证
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











