bigywater.tech
Java · 187

RandomGenerator:Java 随机数算法如何插拔

Java 17 起随机数算法可以按名字插拔(RandomGenerator)。有哪些算法、可复现到什么程度、各自多快、并行任务怎么用?这篇逐项打印出来(SplittableRandom 的并行用途与 SecureRandom 的熵在后面的篇目)。

13 个
JDK 21 里 RandomGeneratorFactory 注册的算法数
16.98 vs 3.1 ns
老的 Random 与 Xoroshiro128PlusPlus 的 nextLong 耗时
UnsupportedOperationException
ThreadLocalRandom.setSeed 的结果

算法清单

实测 · 本机执行输出
  RandomGenerator.getDefault() = L32X64MixRandom
  一共有 13 个注册的算法(RandomGeneratorFactory.all()):
    L128X1024MixRandom         group=LXM          stateBits=1152  equidistribution=1    period=2^1151  统计型
    L128X128MixRandom          group=LXM          stateBits=256   equidistribution=1    period=2^255  统计型
    L128X256MixRandom          group=LXM          stateBits=384   equidistribution=1    period=2^383  统计型
    L32X64MixRandom            group=LXM          stateBits=96    equidistribution=1    period=2^95  统计型
    L64X1024MixRandom          group=LXM          stateBits=1088  equidistribution=16   period=2^1087  统计型
    L64X128MixRandom           group=LXM          stateBits=192   equidistribution=2    period=2^191  统计型
    L64X128StarStarRandom      group=LXM          stateBits=192   equidistribution=2    period=2^191  统计型
    L64X256MixRandom           group=LXM          stateBits=320   equidistribution=4    period=2^319  统计型
    Random                     group=Legacy       stateBits=48    equidistribution=0    period=2^48  统计型
    SecureRandom               group=Legacy       stateBits=2147483647 equidistribution=2147483647 period=2^-1  非确定性
    SplittableRandom           group=Legacy       stateBits=64    equidistribution=1    period=2^64  统计型
    Xoroshiro128PlusPlus       group=Xoroshiro    stateBits=128   equidistribution=1    period=2^127  统计型 可 jump
    Xoshiro256PlusPlus         group=Xoshiro      stateBits=256   equidistribution=3    period=2^255  统计型 可 jump

种子与可复现

实测 · 本机执行输出
  Random               同一个种子 42 创建两个:前 5 个 nextInt(100) = [30, 63, 48, 84, 70] 与 [30, 63, 48, 84, 70] → 一致
  L64X128MixRandom     同一个种子 42 创建两个:前 5 个 nextInt(100) = [98, 1, 80, 2, 55] 与 [98, 1, 80, 2, 55] → 一致
  Xoshiro256PlusPlus   同一个种子 42 创建两个:前 5 个 nextInt(100) = [0, 67, 4, 14, 62] 与 [0, 67, 4, 14, 62] → 一致
  SplittableRandom     同一个种子 42 创建两个:前 5 个 nextInt(100) = [31, 56, 81, 72, 81] 与 [31, 56, 81, 72, 81] → 一致
  new Random(42) 的前 5 个 nextInt(100) = [30, 63, 48, 84, 70](Random 的状态是 48 位,相同种子得到固定的这几个数)
  不同算法同一个种子 42 的第一个 nextLong:[Random=-5025562857975149833, L64X128MixRandom=-5600175640509174766, Xoshiro256PlusPlus=-5479502503263141524, SplittableRandom=-4767286540954276203]
  RandomGenerator.of("L64X128MixRandom") 不指定种子:两次得到的 nextLong 相同吗?false(默认用随机种子)

速度

实测 · 本机执行输出
  Random                 单线程 nextLong():16.98 ns/次
  SplittableRandom       单线程 nextLong():1.98 ns/次
  L32X64MixRandom        单线程 nextLong():6.23 ns/次
  L64X128MixRandom       单线程 nextLong():4.03 ns/次
  L128X1024MixRandom     单线程 nextLong():5.16 ns/次
  Xoshiro256PlusPlus     单线程 nextLong():3.27 ns/次
  Xoroshiro128PlusPlus   单线程 nextLong():3.10 ns/次
  SecureRandom           单线程 nextLong():132.98 ns/次
  ThreadLocalRandom      单线程 nextLong():0.87 ns/次

并行任务

实测 · 本机执行输出
  可跳跃的生成器 Xoshiro256PlusPlus:jumps() 产生 4 个相互独立的子生成器,各自的第一个 nextLong = [5260032071179721131, -2125266420141333252, 3248767060846260542, -7283759719926271074](互不相同)
  可分裂的生成器 L64X128MixRandom:splits() 产生 4 个子生成器,第一个 nextLong = [-3822091268781161973, -5447366426959337576, 9083646920785413712, -1003044473172765812]
  ThreadLocalRandom.current().setSeed(1) → UnsupportedOperationException

分步演示

RandomGenerator
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,单线程循环测速(没有用 JMH,取后 4 轮最好)
    • 没有验证:随机数质量(统计检验,如 PractRand)、多线程下 Random 的竞争开销、JDK 17 与 27 的注册算法差异、nextInt(bound) 的偏差处理、种子的熵来源;耗时是自写循环的一次运行
    京ICP备2026067502号-1京公网安备11010502063487号