bigywater.tech
Java · 310

jcstress:验证并发交错下的可见结果

jcstress 能把「理论上可能」的并发结果真的跑出来。这篇写了 7 个经典测试(Store Buffering、Message Passing、丢失更新、long 撕裂),看哪些结果在本机上实际出现,哪些加上 volatile / release-acquire / 原子类之后消失。

24,354,555
Store Buffering 普通字段下 (0,0) 出现的次数(volatile 下是 0)
1,723
Message Passing 普通字段下观察到的重排序次数(release/acquire 下是 0)
0
AtomicInteger 下丢失更新的次数(普通 int 下是 28,385,172)

jcstress 经典测试

实测 · 本机执行输出
  总耗时 48 秒;CPU 个数:10;jcstress 头部信息: ['Hardware CPUs in use: 10', 'Forks per test: 1 normal, 1 stress', 'Compilation: split', '(CPUs: 10 configured, 9 allocated)', 'Compilation: split', '(CPUs: 10 configured, 9 allocated)']
  [SbPlain] 状态 OK;(0, 0) 24,354,555 Interesting  (0, 1) 9,131,854 Acceptable  (1, 0) 7,553,455 Acceptable  (1, 1) 27 Acceptable
  [SbVolatile] 状态 OK;(0, 0) 0 Forbidden  (0, 1) 9,078,836 Acceptable  (1, 0) 8,305,555 Acceptable  (1, 1) 1,100 Acceptable
  [MpPlain] 状态 OK;(0, 0) 26,152,399 Acceptable  (0, 1) 6,008 Acceptable  (1, 0) 1,723 Interesting  (1, 1) 26,092,561 Acceptable
  [MpRelAcq] 状态 OK;(0, 0) 7,889,419 Acceptable  (0, 1) 2,504 Acceptable  (1, 0) 0 Forbidden  (1, 1) 8,561,728 Acceptable
  [LostUpdatePlain] 状态 OK;(1) 28,385,172 Interesting  (2) 45,258,879 Acceptable
  [LostUpdateAtomic] 状态 OK;(1) 0 Forbidden  (2) 13,811,731 Acceptable
  [LongTear] 状态 OK;(-1) 179,884 Acceptable  (0) 8,204,647 Acceptable

分步演示

jcstress
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,jcstress 0.16,quick 模式(每个测试 1 个 normal fork + 1 个 stress fork),Apple Silicon 10 核;每次运行的出现次数不同(同一个测试两次运行 MP 的 (1,0) 分别是 1 与 1,723 次)
    • 没有验证:default 或 tough 模式下更多交错(quick 模式时间很短)、x86 上同样测试的结果(x86 的 TSO 下 Message Passing 的 (1,0) 通常不会出现,本文没有验证)、JIT 编译级别对结果的影响、其它并发模式(DCL、安全发布等见前面的文章)
    京ICP备2026067502号-1京公网安备11010502063487号