bigywater.tech
Java 内部原理 · 110

Random(seed) 真实验证:相同seed真实产生逐位相同的随机数序列

java.util.Random是伪随机数生成器——"伪"字的真实含义,这篇用相同seed跑两个独立的Random对象,真实验证它们产生的序列是否逐位完全一致,以及这个可重现性在真实工程场景里的价值。

相同seed真实产生完全相同序列
真实验证:两个用seed=12345构造的独立Random对象,各自调用10次nextInt(),真实产生逐位相同的10个数
setSeed()真实能重置到初始状态
真实验证:调用setSeed(999)把Random对象重置回构造时的状态,重置后第一次调用真实和最初的第一次调用结果完全相同

上一篇:Integer.parseInt() 真实验证

真实验证:相同seed,两个独立对象产生逐位相同的序列

用同一个seed分别构造两个完全独立的Random对象,各自生成10个随机数,逐位比对。

RandomSeedDemo.java Random r1 = new Random(12345L); Random r2 = new Random(12345L); for (int i = 0; i < 10; i++) seq1[i] = r1.nextInt(1000); for (int i = 0; i < 10; i++) seq2[i] = r2.nextInt(1000); Arrays.equals(seq1, seq2);
真实实测
相同seed(12345)生成的两个序列真实相等: true
序列内容: [251, 80, 241, 828, 55, 84, 375, 802, 501, 389]

真实结果验证了 Random 的核心设计:它是一个确定性算法(线性同余生成器),内部状态完全由 seed 决定,后续每次调用 nextInt() 都是基于当前内部状态做纯粹的数学运算推导出下一个数,再更新内部状态——整个过程不涉及任何真实的外部随机熵源。两个用相同 seed 构造的、完全独立的 Random 对象,真实产生了逐位相同的序列,这就是"伪随机"这个词的真实含义:看起来杂乱无章,实际上是完全可预测、可重现的。

真实验证:不同seed产生不同序列,不指定seed时基于真实熵源

真实实测
不同seed(54321)生成的序列真实结果: [928, 451, 642, 402, 522, 773, 977, 704, 893, 115]
和seed(12345)的序列真实相等吗: false
两个未指定seed的Random真实产生不同序列: true

真实结果证明了不同的 seed 值真实会推导出完全不同的序列;而不指定 seed 调用 new Random() 时,JDK 真实会用一个基于纳秒级时间戳等系统熵源计算出的值作为默认 seed,所以两次不指定 seed 的构造真实几乎不可能产生相同序列——这也是日常"随机"使用场景里默认应该用的方式。

真实验证:setSeed()真实能把对象重置回初始状态

真实实测
setSeed(999)重置后的第一次nextInt 真实结果: 359,是否等于最初的第一次调用: true

真实结果证明 Random.setSeed() 不只是"设置一个种子影响未来",它真实把对象的内部状态完全重置到了"刚用这个seed构造出来"那一刻的状态——调用 setSeed(999) 之后紧接着的第一次 nextInt(),真实和最初 new Random(999L) 之后的第一次调用给出完全相同的结果。

真实验证:可重现性在Collections.shuffle()里的真实应用

固定seed的Random最大的真实价值场景之一——让"随机"的测试代码变得确定性可复现。

真实实测
用固定seed=42的Collections.shuffle()真实结果: [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
再次用相同seed=42真实结果: [5, 7, 3, 2, 8, 10, 9, 6, 4, 1],两次是否相等: true

ThreadLocalRandom.current() 真实类名: ThreadLocalRandom
真实的工程价值。这组结果验证了 Collections.shuffle(list, random) 这个重载能接受一个外部传入的 Random 实例,而不是每次都用系统默认的不可控随机源——用固定 seed 的 Random 传进去,洗牌结果真实变成完全可复现的,这在真实的单元测试里非常重要:测试代码需要"看似随机但结果确定"的数据,才能写出稳定、可重复运行、断言明确的测试用例,而不是每次运行都得到不同结果导致测试变得不可靠。附带验证了 ThreadLocalRandom(专为高并发场景设计的随机数生成器)真实是一个完全不同的类,它的设计目标是并发性能而不是可重现性,不提供指定 seed 的公开构造方式。

分步演示:两个独立对象是怎么"心有灵犀"的

每一步的数字都是真实调用 nextInt() 得到的结果,不是手工排的。

两个独立的 Random(12345),逐次 nextInt() 的真实结果一位不差
这一步刚生成的数

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到,相同seed的序列和重置行为重复运行完全一致。作为这一批的收尾,系列 Java 内部原理现在共 110 篇。
    • 和String.hashCode() 碰撞那篇一样,属于"看似随机/不可预测的机制,底层其实是完全确定性算法"的真实案例系列。
    • 没有涉及:Random的线性同余算法具体公式和48位内部状态的真实推导过程、Java 17新增的RandomGenerator接口和更现代的算法实现(如L64X128MixRandom)与传统Random的真实性能/质量差异——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号