bigywater.tech
Java · 188

SplittableRandom:为什么适合并行任务

SplittableRandom 为什么适合并行任务?这篇用 1 到 8 个线程的吞吐、5 次运行的可复现性、以及误共用实例时的重复数值,把「分裂」的价值量出来(算法清单与速度对比见上一篇)。

2 vs 8339
8 线程时共享 Random 与每线程 SplittableRandom 的总吞吐(百万次/秒)
5 次相同
每个任务用 split() 出来的生成器时蒙特卡洛结果的复现情况
3565142 个重复
两个线程共用一个 SplittableRandom 时的重复数值总数

多线程吞吐

实测 · 本机执行输出
  线程         共享一个 Random ThreadLocalRandom每线程自己的 SplittableRandom(总吞吐,百万次 nextLong / 秒;每线程各 2000 万次)
  1                   58              1289                  1549
  2                   18              2465                  3086
  4                    6              4836                  5888
  8                    2              7120                  8339

可复现

实测 · 本机执行输出
  split() 出来的 SplittableRandom 蒙特卡洛 π:5 次运行落在圆内的点数 = [31416145, 31416145, 31416145, 31416145, 31416145] → 5 次完全相同
  ThreadLocalRandom        蒙特卡洛 π:5 次运行落在圆内的点数 = [31417628, 31414098, 31412537, 31417972, 31418240] → 5 次互不相同(不可复现)
  共享一个 new Random(7)       蒙特卡洛 π:5 次运行落在圆内的点数 = [31417937, 31417645, 31416853, 31420609, 31419323] → 5 次互不相同(不可复现)

不能共用

实测 · 本机执行输出
  两个线程共用同一个 SplittableRandom:20 次运行里,两个线程拿到相同数值的运行有 20 次,重复数值共 3565142 个
  两个线程各用 split() 出来的:20 次运行里,两个线程拿到相同数值的运行有 0 次,重复数值共 0 个

分步演示

SplittableRandom
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,10 核
    • 没有验证:split() 出来的子生成器之间的统计独立性(没有做统计检验)、ForkJoin 任务里按需 split 的写法、SplittableRandom 的 mix 函数细节、JDK 17 与 27 的数字;吞吐是自写循环的一次运行(后 2 轮取最好)
    京ICP备2026067502号-1京公网安备11010502063487号