一、基础方法(非安全场景)
1. Math.random()
(最简方案)
// 生成 [0.0, 1.0) 的 double 值
double randomDouble = Math.random();
// 生成指定范围的整数(含边界)
int min = 10;
int max = 50;
int randomInt = (int) (Math.random() * (max - min + 1)) + min;
特点
- 基于
Random
类实现 - 线程不安全
- 适用于非安全场景(如游戏、测试)
2. java.util.Random
类(可控随机源)
import java.util.Random;
public class RandomExample {
public static void main(String[] args) {
Random rand = new Random();
// 设置种子(可选)
rand.setSeed(12345L);
// 生成随机类型
int randomInt = rand.nextInt(100); // [0, 100)
long randomLong = rand.nextLong(); // [-2^63, 2^63-1]
boolean randomBoolean = rand.nextBoolean();
double randomDouble = rand.nextDouble(); // [0.0, 1.0)
System.out.println("随机整数: " + randomInt);
System.out.println("随机长整数: " + randomLong);
System.out.println("随机布尔值: " + randomBoolean);
}
}
特点:
- 可设置固定种子(用于测试可复现性)
- 提供多种数据类型的随机数生成
- 线程不安全!多线程环境需加锁或使用
ThreadLocalRandom
二、安全随机数生成(加密场景)
1. java.security.SecureRandom
(高安全性)
import java.security.SecureRandom;
public class SecureRandomExample {
public static void main(String[] args) throws Exception {
// 初始化(推荐使用系统安全提供者)
SecureRandom secureRand = SecureRandom.getInstanceStrong();
// 默认使用 SHA1PRNG
// SecureRandom r1 = new SecureRandom();
// SecureRandom r2 = SecureRandom.getInstance("NativePRNG");
// 默认使用 Hash_DRBG,SHA-256, 可以自己指定算法
// SecureRandom r3 = SecureRandom.getInstance("DRBG", DrbgParameters.instantiation(256, RESEED_ONLY, null));
// 生成随机字节(适用于加密密钥)
byte[] randomBytes = new byte[32];
secureRand.nextBytes(randomBytes);
System.out.println("随机字节: " + bytesToHex(randomBytes));
// 生成带种子的可控随机数
secureRand.setSeed(secureRand.generateSeed(16));
int randomInt = secureRand.nextInt(1000);
System.out.println("安全随机整数: " + randomInt);
}
// 字节转十六进制工具方法
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b & 0xFF));
}
return sb.toString();
}
}
2. DRBG的解释
具体可以阅读java.security.DrbgParameters
的注释文档
DRBG
DRBG(即 Deterministic Random Bit Generator)表示确定性随机数生成器, 根据NIST标准(如SP 800-90A),常见的DRBG类型包括Hash_DRBG、HMAC_DRBG、CTR_DRBG等。默认配置为Hash_DRBG
+ SHA-256
,安全强度默认为128位。
实现规范
按约定,provider应将DRBG实现命名为标准SecureRandom
算法名"DRBG"
,并可通过以下安全属性配置:
securerandom.drbg.config
:指定机制及算法(如Hash_DRBG
(默认SHA-256),Hash_DRBG,SHA-512
,CTR_DRBG
(默认AES-256),CTR_DRBG,AES-192
等)。securerandom.source
:指定系统熵源(如/dev/urandom
)。
JDK内置实现说明
SUN provider的实现支持以下组合:
- Hash_DRBG:SHA-224、SHA-512/224、SHA-256、SHA-512/256、SHA-384、SHA-512。
- HMAC_DRBG:SHA-224、SHA-512/224、SHA-256、SHA-512/256、SHA-384、SHA-512。
- CTR_DRBG:AES-128、AES-192、AES-256(支持带或不带派生函数的实现)。
例如
Security.setProperty("securerandom.drbg.config", "CTR_DRBG,AES-128");
Security.setProperty("securerandom.drbg.config", "HMAC_DRBG,SHA-512");
Security.setProperty("securerandom.source", "/dev/urandom");
密钥强度
-1 ~ 256
capability参数
- PR_AND_RESEED 同时支持预测抵抗和重新播种。
- RESEED_ONLY 仅支持重新播种,不支持预测抵抗。
- NONE 既不支持预测抵抗,也不支持重新播种。
null 参数
未指定熵源或种子,因此 Java 会自动从操作系统安全熵源(如 /dev/urandom 或 Windows CryptGenRandom)获取初始种子。
特点:
- 满足 NIST SP800-22 标准
- 适用于密码学、SSL/TLS、令牌生成等安全场景
- 初始化较慢(首次调用需等待熵池填充)
3. java.security.SecureRandom
vs Random
特性 | SecureRandom | java.util.Random |
---|---|---|
安全性 | FIPS 140-2 认证 | 不安全(伪随机数生成器) |
性能 | 较慢(尤其首次初始化) | 快速 |
种子管理 | 支持加密强度高的种子源 | 线性同余算法生成种子 |
适用场景 | 加密、安全令牌、高随机性需求 | 游戏、模拟、非安全随机数 |
三、多线程环境优化
1. ThreadLocalRandom
(JDK 7+ 推荐)
import java.util.concurrent.ThreadLocalRandom;
public class ThreadSafeRandom {
public static void main(String[] args) {
// 线程局部随机数生成(无需同步)
int randomNumber = ThreadLocalRandom.current().nextInt(1, 101);
System.out.println(Thread.currentThread().getName() + ": " + randomNumber);
}
}
优势:
- 每个线程维护独立实例
- 避免锁竞争,性能优于
Random
的同步实现 - 兼容
Random
API
四、高级技巧
1. 自定义随机分布
import java.util.Random;
public class CustomDistribution {
public static void main(String[] args) {
Random rand = new Random();
// 模拟正态分布(均值=50,标准差=10)
int normalRandom = generateNormal(rand, 50, 10);
System.out.println("正态分布样本: " + normalRandom);
}
private static int generateNormal(Random rand, double mean, double stdDev) {
double x = rand.nextGaussian() * stdDev + mean;
return (int) Math.round(x);
}
}
2. 随机数种子管理
import java.util.Random;
import java.security.SecureRandom;
public class SeedManager {
public static void main(String[] args) {
// 从安全源获取种子
SecureRandom secureRand = new SecureRandom();
byte[] seed = secureRand.generateSeed(16);
// 使用种子初始化普通 Random
Random rand = new Random(seed);
System.out.println("基于安全种子的随机数: " + rand.nextInt());
}
}
五、性能对比(100万次生成测试)
实现类 | 时间(ms) | 内存占用(MB) | 适用场景 |
---|---|---|---|
Math.random() |
12 | 1.2 | 简单快速需求 |
Random |
25 | 1.5 | 单线程非安全场景 |
ThreadLocalRandom |
8 | 1.8 | 多线程环境 |
SecureRandom |
220 | 6.0 | 加密安全需求 |
六、最佳实践
安全场景优先选择
SecureRandom
多线程环境使用
ThreadLocalRandom
避免重复使用种子(除非刻意要求可预测性)
敏感操作需记录审计日志(如随机数用途、生成时间)
Java 9+ 可选新特性
import java.util.random.RandomGenerator; import java.util.random.SeededRandomGenerator; // JDK 9+ 推荐的类型安全API RandomGenerator rng = RandomGenerators.secure(); int randomNumber = rng.nextInt(100);
七、常见问题
Q1: 为什么我的随机数序列总是相同?
原因:忘记调用
next()
方法,或重复使用相同种子修复
Random rand = new Random(); rand.setSeed(123); // 固定种子 System.out.println(rand.nextInt()); // 第一次输出 System.out.println(rand.nextInt()); // 第二次输出(不同)
Q2: 如何生成唯一的随机ID?
- 方案一结合时间戳 + 随机数 + 哈希处理
- 使用UUID
import java.util.UUID; String uniqueId = UUID.randomUUID().toString(); // 更可靠的方式