核心内容摘要
【毕业设计】基于springboot的校园闲置物品租售系统(源码+文档+远程调试,全bao定制等)
深入理解 Java 虚拟机内存模型JMM—— 从底层原理到多线程实战2026 年视角Java 内存模型Java Memory Model简称 JMM是 JVM 规范中定义的抽象模型它屏蔽了底层硬件如 CPU 缓存、内存的差异让 Java 程序在多线程环境下实现一致性、可见性和原子性。
JMM 不是 JVM 的物理内存结构堆、栈等而是关于线程如何访问共享变量的规则。
很多人把 JMM 和 JVM 内存区域混淆了——前者是并发模型后者是内存布局。
今天我们先快速区分一下然后深入 JMM 的核心原理、happens-before 规则、volatile / synchronized 的底层实现以及常见坑与优化基于 Java 21/22 的最新特性。
分JVM 内存布局 vs JMM 的快速区分避免初学者混淆JVM 物理内存区域Runtime Data Area是 JVM 运行时数据存储的地方JMM 是基于这些区域定义的线程间交互规则。
维度JVM 内存布局物理区域Java 内存模型JMM抽象规则核心关注数据存储在哪里线程如何安全访问共享数据典型组件程序计数器、虚拟机栈、本地方法栈、堆、元空间方法区主内存、工作内存、happens-before 关系线程私有/共享栈/计数器私有堆/元空间共享所有线程共享主内存每个线程有工作内存
常见问题OOMOutOfMemoryError可见性问题、重排序、原子性失效JVM 内存布局简图物理视角线程私有程序计数器PC Register、虚拟机栈VM Stack、本地方法栈Native Method Stack线程共享堆Heap、元空间MetaspaceJava 8 取代 PermGen
分JMM 的核心抽象概念JMM 定义了主内存Main Memory和线程工作内存Working Memory的交互主内存所有共享变量的“官方”存储地堆中对象、静态变量等。
线程工作内存每个线程的私有高速缓存副本类似 CPU 缓存包含从主内存读入的变量副本。
为什么需要 JMM现代 CPU/编译器会优化代码如指令重排序、缓存一致性导致多线程下变量可见性问题。
JMM 通过8 种原子操作规范这些行为lock锁定主内存变量标记为线程独占。
unlock解锁释放独占状态。
read读取主内存 → 工作内存。
load加载工作内存中放入 read 的变量。
use使用工作内存变量传递给执行引擎。
assign赋值执行引擎结果放回工作内存。
store存储工作内存 → 主内存传输。
write写入store 的变量写入主内存。
JMM 的三大特性面试必考原子性Atomicity操作不可中断但 JMM 不保证普通变量的原子性只保证基本读写。
可见性Visibility一个线程修改变量后其他线程立即可见volatile 保证。
有序性Ordering程序执行顺序符合代码顺序防止重排序volatile/synchronized 保证。
分happens-before 规则JMM 的灵魂解决可见性/有序性happens-beforehb是 JMM 定义的偏序关系如果 A hb B则 A 的结果对 B 可见且 A 在 B 前执行但不一定是时间顺序。
8 大 happens-before 规则Java 规范 JSR-133 定义Java 21 无变化程序顺序规则同一个线程内前一个操作 hb 后一个as-if-serial。
监视器锁规则unlock hb 后续的 locksynchronized 块。
volatile 变量规则volatile 写 hb 后续的读。
线程启动规则Thread.start() hb 线程内第一个操作。
线程终止规则线程内所有操作 hb Thread.join() 或 isAlive()false。
线程中断规则interrupt() hb 被中断线程的 interrupted()true。
对象终结规则对象构造函数结束 hb finalize()。
传递性A hb B 且 B hb C → A hb C。
示例代码可见性问题演示classVisibilityDemo{privateintx0;// 无 volatile → 可能不可见publicvoidwriter(){x42;// 线程 A 执行}publicvoidreader(){if(x
{// 线程 B 可能永远读不到 42重排序/缓存System.out.println(看到了);}}}// 修复加 volatileprivatevolatileintx0;// 写后立即刷新主内存读前从主内存加载
分volatile 的底层实现与局限性volatile 保证可见性 部分有序性禁止重排序但不保证原子性如 i 不是原子。
底层机制基于硬件内存屏障Memory Barriervolatile 写插入 StoreStore前写不重排后写 StoreLoad前写不重排后读。
volatile 读插入 LoadLoad前读不重排后读 LoadStore前读不重排后写。
在 x86 CPU 上通过 lock 前缀指令实现类似 MESI 缓存一致性协议。
volatile 的局限不适合复合操作如 i read-modify-write非原子。
替代用 AtomicIntegerCAS volatile。
Java 21 新特性VarHandle / Virtual ThreadsProject Loom对 volatile 的优化但核心不变。
分synchronized 的底层实现Monitorsynchronized 保证原子性 可见性 有序性。
三种用法实例方法锁 this。
静态方法锁 Class 对象。
代码块锁指定对象。
底层MonitorEnter / MonitorExit 字节码基于对象头Object Header的 Mark Word存储锁状态、hashcode 等。
锁优化Java 6偏向锁无竞争时Mark Word 存线程 ID。
轻量级锁少竞争用 CAS 自旋。
重量级锁多竞争用 OS 互斥量Mutex线程阻塞。
锁粗化/消除JIT 编译器优化。
示例classCounter{privateintcount0;publicsynchronizedvoidincrement(){// 保证原子性count;}}
分常见坑与生产优化2026 年实战视角常见坑双重检查锁定DCL问题单例模式中未 volatile 的 instance 可能部分初始化重排序。
privatevolatilestaticSingletoninstance;// 必须 volatilepublicstaticSingletongetInstance(){if(instancenull){synchronized(Singleton.class){if(instancenull){instancenewSingleton();// new 分配 初始化 赋值重排序风险}}}returninstance;}long/double 的非原子性64 位变量在 32 位 JVM 上非原子JMM 允许拆成两次 32 位写用 volatile 修复。
伪共享False Sharing线程缓存行64 字节导致的性能损失用 ContendedJava 8或 padding 变量优化。
生产优化用 ConcurrentHashMap / CopyOnWriteArrayList 代替 synchronized 集合。
Java 21 虚拟线程Virtual Threads轻量级线程减少上下文切换但 JMM 规则不变。
工具JMH 基准测试可见性问题JFRJava Flight Recorder监控锁争用。
参数-XX:UseBiasedLocking启用偏向锁Java 15 默认关。
小结对比表便于记忆机制保证原子性保证可见性保证有序性开销适用场景volatile否是部分低标志位、状态变量synchronized是是是中高互斥代码块Atomic*是CAS是是中计数器、简单更新Lock (ReentrantLock)是是需 volatile是中更灵活控制如读写锁写到这里JMM 的核心就讲透了。
理解 JMM 是掌握 Java 并发的基础能帮你避开 80% 的多线程 Bug。
重阳你现在项目里用的是 Java 21 还是 22有没有遇到过 JMM 相关的生产问题如可见性导致的诡异 Bug或者想深入聊聊虚拟线程对 JMM 的影响来分享你的经验