jmm通过happens-before规则保障可见性、原子性和有序性,volatile仅解决可见性与有序性但不保证原子性,synchronized则兼具三者且提供更强同步语义。

Java 内存模型(JMM)本身不直接“编写代码”,但它提供了一套规则,让开发者能**有依据地写出线程安全的并发代码**。其中,内存可见性是三大核心问题(可见性、原子性、有序性)中最基础也最常被忽视的一环。只要变量修改对其他线程“及时可见”,很多死循环、状态失效、读到陈旧值的问题就能避免。
用 volatile 保证关键状态的即时可见
当一个布尔标志、开关信号或就绪状态需要被多个线程读写时,必须声明为 volatile。它强制每次读取都从主内存加载最新值,每次写入都立即刷新到主内存,并插入内存屏障防止重排序。
- 比如停止线程的 flag:
private volatile boolean running = true;—— 否则子线程可能永远卡在while(running)中 - 再如初始化完成标志:
private volatile boolean initialized = false;,配合普通变量赋值,可安全实现双重检查锁之外的轻量初始化 - 注意:volatile 不能替代 synchronized 来保护复合操作(如
i++),它只保单次读/写操作的可见性与禁止重排
借助同步块(synchronized)天然获得可见性保障
进入 synchronized 块前,线程会清空工作内存中该锁保护的所有共享变量副本;退出时,会把修改强制刷回主内存。这意味着:所有被同一把锁保护的变量,在锁释放后对下一个获取该锁的线程必然可见。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 适用于需要原子性 + 可见性组合的场景,例如计数器更新、对象状态切换
- 即使锁内只读不写,也能确保看到之前持有该锁线程写入的最新值(基于监视器锁规则)
- 比 volatile 更重,但语义更强、适用范围更广
利用 happens-before 规则主动建立可见性链
JMM 不靠“实时同步”,而是靠操作间的偏序关系来保证结果可见。只要 A happens-before B,那么 A 的写就对 B 的读可见。常见可靠链路包括:
- volatile 写 → 后续任意线程对该 volatile 变量的读
- 解锁(synchronized 退出)→ 后续同锁的加锁(进入)
- Thread.start() → 新线程中所有操作
- Thread.join() → 主线程中 join 调用之后的操作
- 这些规则可传递组合:A HB B,B HB C ⇒ A HB C,可用于构建跨多线程的数据发布逻辑
避免依赖未同步的普通变量读写
普通字段(非 volatile、未受锁保护)的读写之间没有 happens-before 关系。编译器和 CPU 可能重排、缓存、延迟写入——导致另一线程看到部分更新、乱序结果甚至永远看不到更新。
- 典型陷阱:
int x = 0; boolean ready = false;先设 x=42 再设 ready=true,但无同步时,其他线程可能看到 ready==true 却 x==0 - 修复方式:将 ready 声明为 volatile,即可借助 volatile 规则让 x=42 对后续读 ready 的线程可见(因程序顺序 + volatile 规则共同作用)
- 不要试图靠 sleep、yield 或复杂逻辑“等一等”来解决可见性——这是不可靠且反模式的做法
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










