jmm不是可配置的模块,而是一套由volatile、synchronized、final等关键字和线程操作触发的抽象规范,通过内存屏障和happens-before关系约束并发行为,其实践核心在于语义使用、缓存行隔离(如@contended)、实测验证(jmh/perf)及并发粒度优化。

Java 内存模型(JMM)不是靠“配”出来的,它是一套规范,不能像 JVM 参数那样直接配置。所谓“通关演练”,本质是理解规则 + 验证行为 + 控制代码结构。重点不在配置项,而在设计决策和验证手段。
明确 JMM 的边界:它不提供开关,只定义约束
JMM 不是 JVM 的一个可调模块,没有 -XX:+UseJMM 这类参数。它通过语言关键字(volatile、synchronized、final)、锁机制、线程操作(start/join)等触发底层内存屏障和 happens-before 关系。你“配”的其实是这些语义的使用方式:
- 用
volatile字段替代普通变量,强制读写走内存屏障路径 - 用
synchronized块包裹共享状态变更,建立锁内操作对后续获取该锁线程的可见性 - 启动线程前完成初始化,依赖 start 规则 而非额外加锁
- 等待子线程结束时用
join(),而非轮询或 sleep,获得天然 happens-before 保障
关键字段布局:靠填充或注解“配”出缓存行隔离
伪共享虽属硬件层问题,但 JMM 实践中必须应对。这里才有真正可“配”的动作:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 手动填充:在高频修改字段(如
volatile long head)前后插入 7 个long字段(56 字节),凑够 64 字节缓存行边界 - @Contended 注解:JDK 8+ 中标记字段或类,配合启动参数
-XX:+UnlockExperimentalVMOptions -XX:+UseContended,让 JVM 自动插入填充 - 避免误判:声明顺序 ≠ 内存顺序,必须用 JOL(Java Object Layout) 工具验证真实偏移,例如:
java -jar jol-cli.jar internals MyCounter
验证比配置更重要:三类实测手段缺一不可
没有观测的优化等于空谈。JMM 效果必须靠实证:
-
JMH 基准测试:对比加
@Contended前后吞吐量、标准差——伪共享常导致性能抖动剧烈,而非单纯下降 -
perf stat:运行时采集
cache-misses和cache-references,命中率骤降往往指向缓存行争用 - 字段偏移检查:确认目标字段是否真被隔离到独立缓存行,而不是靠经验猜测
并发粒度控制:这是最有效的“软配置”
减少总线风暴和伪共享影响,核心是降低对同一内存位置的竞争频率:
- 用 LongAdder 替代
AtomicInteger做计数,把竞争分散到 cell 数组 - 环形缓冲区中分离
producerIndex和consumerIndex,确保不共用缓存行 - 状态标志避免轮询,改用
LockSupport.parkNanos()或条件队列 - 复合状态更新封装进不可变对象 +
AtomicReference,避免字段间重排序和中间态暴露
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










