可见性问题本质是线程修改共享变量后其他线程无法及时感知,根源在于jmm中工作内存与主内存分离、无强制同步机制,导致修改未“发布”;volatile、synchronized等通过内存屏障和happens-before规则保障可见性。

可见性问题的本质,是线程对共享变量的修改没有“发布”出去——不是没改,而是改了别人看不见。
工作内存与主内存的分离导致读写错位
Java 内存模型(JMM)规定:所有变量都存于主内存,每个线程拥有自己的工作内存(如 CPU 缓存、寄存器副本)。线程操作变量时,实际是在自己工作内存中读写,而非直接访问主内存。
- 线程 A 修改变量 → 更新的是自己工作内存中的副本 → 是否刷回主内存,时机不确定
- 线程 B 读取变量 → 加载的是自己工作内存中的旧副本 → 可能从未同步过主内存最新值
- 主内存不会主动推送更新给其他线程;各线程之间不共享缓存,也不自动拉取
CPU 缓存与编译器优化加剧延迟
硬件和 JVM 层面的优化,在单线程下提升性能,却破坏了多线程下的观察一致性:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- CPU 多级缓存使不同核心看到同一变量的不同副本,缺乏缓存一致性协议(如 MESI)的显式触发时,更新长期滞留本地
- JIT 编译器可能将 while(!flag) 优化为常量判断(如假设 flag 永远为 false),跳过每次重新读取主内存
- 指令重排序让写 flag = true 被移到逻辑后方,或与其它语句交换顺序,使其他线程在“应看到更新”的时刻仍读到旧值
没有 happens-before 关系就无法建立可见保障
JMM 不保证任意两个操作之间的可见性,只通过 happens-before 规则提供确定性:
- 普通字段读写之间无 happens-before 关系 → 线程 B 无法保证看到线程 A 的写操作结果
- volatile 写 → happens-before 后续 volatile 读,强制刷新与重载
- synchronized 解锁 → happens-before 后续加锁,清空并重载受保护变量
- 缺少这些规则锚点,JVM 和 CPU 就按最优路径执行,忽略跨线程感知需求
典型表现就是“永远不退出的循环”
比如一个 boolean running = true 字段被主线程设为 false,但工作线程仍在 while(running) 中死循环——它始终读取自己缓存里的 true,因为没有机制告诉它:“该去主内存看看了”。这不是 bug,而是 JMM 在无同步前提下的默认行为。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










