Skip to content

jcstress-safe-publication ​

1. 实验目标与工程要点 ​

本实验用 jcstress(OpenJDK 并发压力测试框架)实测「对象未安全发布」时会出现的异常可见结果,直观证明模块 07 的核心论断:JMM 问题不能靠肉眼推理,必须用工具实测。

我们写两个几乎一样的 @JCStressTest:

用例发布方式预期教学点
UnsafePublishHolder 引用非 volatile可能出现 r1=0(读到 null 或半初始化对象)数据竞争下,引用赋值与构造体可能被重排
SafePublishHolder 引用 volatiler1=0 被标记为 FORBIDDEN,不应出现volatile 禁止重排,读者一定看到完全构造好的对象

jcstress 会用大量线程组合反复跑这两个用例,把每种结果的出现次数统计出来。


2. 深入原理与生活浅显比喻 ​

2.1 搬家比喻 ​

你(写线程)把家具搬进新家,然后在门上挂了「我搬好了」的牌子(把引用赋值给共享变量):

  • 不安全发布:你挂牌子的时候,沙发还没搬完(构造体未执行完)。邻居(读线程)看到牌子就冲进来,发现客厅空着——他以为你没搬(读到半初始化 / 默认值)。
  • 安全发布(volatile) :规定「必须先搬完所有家具,才能挂牌子」。邻居看到牌子时,家里一定齐了。

volatile 在这里不是「锁」,而是给编译器和 CPU 下了一道顺序禁令:引用赋值必须排在构造完成之后,且对其他线程立即可见。

2.2 为什么「看代码觉得没问题」会骗你 ​

单线程下 new Holder() 当然先构造完再赋值。但 JVM/CPU 为了性能可以重排,且每个核心有自己的缓存。没有 happens-before 关系时,另一个线程完全可能以「先看到引用、后看到字段」的顺序观察。这种 bug 在本地 99% 不出现,上线后偶发脏数据——这正是 jcstress 存在的意义:用穷举式的并发组合把小概率变成必现。


运行前置条件 ​

本实验依赖 OpenJDK jcstress 框架(见 pom.xml),jcstress 借助自身 harness 运行, 不能裸 javac / java 跑,必须经 Maven 构建。前置依赖:

依赖要求自检命令
JDK11+java -version
Apache Maven3.xmvn -version
网络首次需下载 jcstress-core 等依赖—

推荐用仓库提供的 run.sh 作为统一入口,它会自动检测 mvn:

  • 检测到 mvn:直接执行 mvn clean verify,完成编译并运行所有 @JCStressTest。
  • 未检测到 mvn:打印友好提示并退出(exit 1),提示需要 JDK 11+ 与 Maven; macOS 可用 brew install maven 安装,其他平台参考 Maven 官方安装文档。
bash
cd labs/java/runtime-concurrency/jcstress-safe-publication
./run.sh

3. 动手步骤 ​

本实验需要一个最小 Maven 模块(jcstress 借助 harness 运行,不能裸 java 跑)。

推荐入口是上一节「运行前置条件」的 run.sh:自动检测 mvn,缺失时给出 JDK 11+ / brew install maven 的友好提示。手动等价命令:

bash
cd labs/java/runtime-concurrency/jcstress-safe-publication
mvn clean verify        # 下载 jcstress 依赖并运行所有 @JCStressTest

运行结束后,jcstress 会在控制台与 target/jcstress-results/ 输出每个用例的结果分布,形如:

text
UnsafePublish
  (cases, 0)    => ACCEPTABLE_INTERESTING  (发生过:读到 null / 半初始化)
  (cases, 1)    => ACCEPTABLE

SafePublish
  (cases, 0)    => FORBIDDEN               (理论上不应发生)
  (cases, 1)    => ACCEPTABLE

关注 UnsafePublish 里 0 是否真的发生——一旦发生,就坐实了「肉眼推理不可靠」。

若不想引入 Maven,也可单独 javac 编译后用 java -jar jcstress.jar 运行(需自备 jcstress harness jar),详见 pom.xml 与官方示例。


4. 源码 ​


5. 对应知识库文档 ​

站点构建时间:2026/8/24 23:43:17