Collections.shuffle()
打乱有序序列(如1-100),2. 使用Set
集合存储并校验重复值,3. 使用ThreadLocalRandom
或SecureRandom
配合循环检测,4. 利用数据库自增ID或UUID保证唯一性,需根据场景选择合适方案,如抽奖推荐洗牌算法,ID生成推荐UUID。基于集合的洗牌算法(小范围高效)
原理:预生成所有可能值,随机打乱顺序后顺序取出
适用场景:有限且范围小的数据集(如1-100的抽奖)
List<Integer> numbers = new ArrayList<>(); for (int i = 1; i <= 100; i++) { // 预填充数据 numbers.add(i); } Collections.shuffle(numbers); // 随机打乱 // 按序取出不重复值 for (int num : numbers) { System.out.println(num); }
优点:O(n)时间复杂度,绝对不重复
缺点:内存占用高,不适用大范围(如10亿)
HashSet去重(动态生成)
原理:生成随机数后存入Set自动去重
Set<Integer> uniqueSet = new HashSet<>(); Random rand = new Random(); while (uniqueSet.size() < 50) { // 目标50个不重复数 int num = rand.nextInt(1000); // 范围[0,999] uniqueSet.add(num); }
注意:
- 集合大小接近范围上限时,性能急剧下降(碰撞概率高)
- 需设置最大循环次数避免死循环
线性同余生成器(LCG)定制
原理:通过数学公式控制随机序列不重复
// 自定义LCG参数 (a, c, m需符合Hull-Dobell定理) class CustomLCG { private long seed; private final long a = 1664525, c = 1013904223, m = (long) Math.pow(2, 32); public CustomLCG(long seed) { this.seed = seed; } public int nextUnique() { seed = (a * seed + c) % m; // 生成下一个数 return (int) (seed % 10000); // 限制范围 } } // 使用示例 CustomLCG generator = new CustomLCG(System.currentTimeMillis()); Set<Integer> results = new HashSet<>(); while (results.size() < 1000) { results.add(generator.nextUnique()); }
适用场景:需要可预测序列的场景(如游戏关卡生成)
风险:参数选择不当会导致周期缩短
安全随机数(高安全性场景)
原理:用SecureRandom
生成密码学强度的随机数
SecureRandom secureRandom = new SecureRandom(); Set<Integer> secureSet = new HashSet<>(); while (secureSet.size() < 10) { int num = secureRandom.nextInt(100_000); secureSet.add(num); }
优势:抵御预测攻击,适用于令牌、密钥生成
代价:性能比Random
低10倍以上
位图法(BitMap)超大范围优化
原理:用比特位标记已生成数字,节省内存
BitSet bitSet = new BitSet(1_000_000); // 100万范围 Random rand = new Random(); int count = 0; while (count < 10_000) { // 目标1万个不重复数 int num = rand.nextInt(1_000_000); if (!bitSet.get(num)) { bitSet.set(num); // 标记已使用 count++; } }
优势:内存压缩至传统数组的1/32
适用:范围大但样本稀疏的场景(如百万中取1万)
关键注意事项
- 性能陷阱
HashSet去重在覆盖率>70%时碰撞率飙升,应改用洗牌或BitMap
- 随机性质量
- 普通
Random
类周期为2⁴⁸,优先用ThreadLocalRandom
(Java7+)
- 普通
- 并发场景
- 多线程下使用
SplittableRandom
(Java8+)避免竞争
- 多线程下使用
- 分布式系统
需结合数据库唯一约束或Snowflake算法,单机随机无法保证全局唯一
方法选型建议
场景 | 推荐方法 |
---|---|
小范围全量采样(<10⁶) | 洗牌算法(Collections.shuffle) |
大范围稀疏采样 | BitMap位图法 |
安全敏感场景 | SecureRandom + HashSet |
可预测序列需求 | 自定义LCG |
引用说明:
- LCG参数选择参考《计算机程序设计艺术》卷2(Donald Knuth)
- 安全随机数标准遵循NIST SP 800-90A Rev.1
- 并发随机数生成器设计基于Java官方文档
通过科学选择算法,可平衡性能、内存与安全性需求,实际开发中需严格测试边界条件(如范围溢出、线程竞争),避免业务逻辑漏洞。
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/31831.html