Collections.shuffle 默认以 System.nanoTime() 为种子,结果不可重现;需可复现时应传入固定种子的 Random 实例,如 Collections.shuffle(list, new Random(12345L)),其基于 Fisher–Yates 算法,保证均匀打乱。

Java 中 Collections.shuffle 默认使用当前时间纳秒作为种子创建 Random 实例,因此每次调用结果不可重现;若需可复现的随机打乱(如测试、调试或分布式环境一致性场景),必须显式传入带固定种子的 Random 对象。
默认 shuffle 的随机性来源
调用 Collections.shuffle(list) 时,内部等价于:
new Random().nextInt(n)
该 Random 实例以 System.nanoTime() 为种子,毫秒级并发下可能重复,且无法跨 JVM 或跨运行复现结果。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
用指定种子实现可重现打乱
传入带固定种子的 Random 实例即可保证相同输入 List 总得到相同顺序:
立即学习“Java免费学习笔记(深入)”;
- 使用
Collections.shuffle(list, new Random(12345L)) - 种子值任意 long 类型,建议用有意义的常量或配置项(如测试用例编号)
- 同一种子 + 同一原始 List + 同一 JDK 版本 → 打乱结果完全一致
算法本质:Fisher–Yates 洗牌(原地版本)
Collections.shuffle 实际采用优化的 Fisher–Yates 算法(也称 Knuth Shuffle),时间复杂度 O(n),均匀分布:
- 从列表末尾开始,对每个位置 i(i 从 list.size()-1 递减到 1),随机选一个索引 j ∈ [0, i]
- 交换 list[i] 和 list[j]
- 该过程不依赖外部随机源质量,但依赖
Random.nextInt(bound)的均匀性
注意事项与常见误区
- 传入的
Random实例可复用,无需每次新建(避免无谓对象开销) - 不要用
Math.random()或ThreadLocalRandom.current()替代 —— 它们不支持设种子 - JDK 17+ 中
Random默认使用 LXM 算法,但shuffle行为兼容;若需更强随机性(如密码学场景),应自行实现并用SecureRandom,但注意其性能开销大且不保证 shuffle 均匀性(因SecureRandom.nextInt()实现差异)

















