Java 中随机数生成:零基础入门到精通(2025-2026 最新实用指南)
Java 提供了多种生成随机数的方式,从最古老的 java.util.Random 到现代推荐的 java.util.concurrent.ThreadLocalRandom,再到加密级别的 SecureRandom,每一种都有自己的适用场景。
下面按“使用频率 + 推荐程度”排序,带你从入门用到精通。
1. 目前(2025-2026)最推荐的几种方式对比
| 方式 | 类名 | 线程安全 | 性能 | 适用场景 | 推荐指数 | 备注 |
|---|---|---|---|---|---|---|
| ThreadLocalRandom | java.util.concurrent.ThreadLocalRandom | 是(每个线程独立) | ★★★★★ | 99% 的业务场景(游戏、模拟、抽奖、测试数据) | ★★★★★ | 现代首选 |
| Random | java.util.Random | 否(有锁) | ★★★ | 单线程或对性能要求不高 | ★★★ | 历史遗留代码常见 |
| SplittableRandom | java.util.SplittableRandom | 是 | ★★★★ | 并行流 + 大规模随机数生成 | ★★★★ | Java 8 引入,适合 Stream 并行 |
| SecureRandom | java.security.SecureRandom | 是 | ★★ | 密码学、安全相关(token、盐、nonce) | ★★★ | 唯一加密安全随机数生成器 |
| Math.random() | java.lang.Math | 否(内部用 Random) | ★★★ | 非常简单的脚本/教学场景 | ★★ | 不推荐在正式项目中使用 |
2. 代码示例 – 各种场景最推荐写法(直接复制用)
方式一:ThreadLocalRandom(99% 场景首选)
import java.util.concurrent.ThreadLocalRandom;
// 1. 随机整数 [0, n)
int num = ThreadLocalRandom.current().nextInt(100); // 0 ~ 99
// 2. 指定范围 [min, max)
int score = ThreadLocalRandom.current().nextInt(60, 101); // 60 ~ 100
// 3. 随机 long
long bigNum = ThreadLocalRandom.current().nextLong();
// 4. 随机 double [0.0, 1.0)
double d = ThreadLocalRandom.current().nextDouble();
// 5. 随机 boolean
boolean coin = ThreadLocalRandom.current().nextBoolean();
// 6. 随机 float [0.0f, 1.0f)
float f = ThreadLocalRandom.current().nextFloat();
// 7. 高斯分布(正态分布)- 常用于模拟身高、体重、考试分数
double height = ThreadLocalRandom.current().nextGaussian() * 10 + 170; // 均值170cm,标准差10
方式二:经典 Random(老项目常见)
import java.util.Random;
Random rand = new Random(); // 建议只创建一个实例,不要每次都 new
// 基本用法同上,只是把 ThreadLocalRandom.current() 换成 rand
int n = rand.nextInt(100);
double d = rand.nextDouble();
重要:不要在循环里反复 new Random(),会产生大量重复或低质量随机数。
方式三:SecureRandom(安全敏感场景)
import java.security.SecureRandom;
import java.util.Base64;
SecureRandom sr = new SecureRandom();
// 生成 32 字节随机盐(密码哈希常用)
byte[] salt = new byte[32];
sr.nextBytes(salt);
// 转 base64 常用于 token
String token = Base64.getUrlEncoder().withoutPadding().encodeToString(salt);
常见写法对比(记住这个就够了)
// 错误示范(低质量 + 性能差)
for (int i = 0; i < 10000; i++) {
new Random().nextInt(100); // 千万别这样写
}
// 推荐示范
ThreadLocalRandom.current().nextInt(100); // 简洁、安全、高性能
3. 常见需求一站式解决方案
| 你想要的效果 | 推荐写法(2025-2026) | 说明 |
|---|---|---|
| 随机整数 [min, max] | ThreadLocalRandom.current().nextInt(min, max + 1) | 注意要 +1 |
| 从 List/Set 随机取一个元素 | list.get(ThreadLocalRandom.current().nextInt(list.size())) | 最简洁 |
| 按权重随机(抽奖、掉落) | 用 Alias Method 或自己写累加权重 + 二分查找(或用第三方库) | ThreadLocalRandom.nextDouble() 判断区间 |
| 随机打乱数组/List | Collections.shuffle(list, ThreadLocalRandom.current()) | 线程安全版 |
| 生成随机字符串(验证码、盐) | 用 SecureRandom + Base64 或自定义字符集 | 安全场景必用 SecureRandom |
| 模拟高斯分布(考试成绩、身高) | ThreadLocalRandom.current().nextGaussian() * 标准差 + 均值 | 非常常用 |
| 并行流中生成随机数 | SplittableRandom 或 ThreadLocalRandom(后者更简单) | 避免锁竞争 |
4. 经典面试/源码追问
- 为什么不推荐反复 new Random()?
→ 种子如果太接近(纳秒级),随机序列高度重复;而且有锁,性能差。 - ThreadLocalRandom 为什么比 Random 快很多?
→ 每个线程有独立的随机数种子和状态,无锁竞争。 - Math.random() 底层是什么?
→new Random().nextDouble()的封装(单例 Random),不推荐在高并发使用。 - 如何生成不重复的随机数(比如随机抽 10 张不重复的牌)?
→ 首选:Collections.shuffle整个集合后取前 n 个
→ 次选:用 Set 循环生成直到达到数量(效率较低) - 生成 6 位数字验证码最推荐写法?
String code = String.format("%06d", ThreadLocalRandom.current().nextInt(1000000));
5. 快速记忆口诀(背下来就够了)
- 普通业务随机数 → ThreadLocalRandom.current().nextXxx()(最常用)
- 安全相关(密码、token、盐) → SecureRandom
- 并行流 / 大数据量 → SplittableRandom 或 ThreadLocalRandom
- 老项目/简单脚本 → Random 或 Math.random()
- 永远不要在循环里 new Random()
你现在最常遇到的随机数场景是哪一种?
- 游戏掉落/抽奖?
- 测试数据生成?
- 验证码/唯一码?
- 按权重随机?
- 高并发场景?
告诉我具体需求,我可以给你最优写法或完整小例子。