1. Math.random()
产生的随机数是 [0,1) 之间的一个 double,即 0 <= random < 1。
实现原理:
当第一次调用 Math.random() 方法时,自动创建了一个伪随机数生成器,实际上用的是 new java.util.Random()。当接下来继续调用 Math.random() 方法时,就会使用这个新的伪随机数生成器。
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
}
在多线程情况下,只有一个线程会负责创建伪随机数生成器(使用当前时间作为种子),其他线程则利用该伪随机数生成器产生随机数。因此 Math.random() 方法是线程安全的。
2. java.util.Random 工具类
在java.util这个包里面提供了一个Random的类,我们可以新建一个Random的对象来产生随机数,他可以产生随机整数、随机float、随机double,随机long,这个也是我们在j2me的程序里经常用的一个取随机数的方法。
基本算法:
linear congruential pseudorandom number generator (LGC) 线性同余法伪随机数生成器
缺点:
可预测。从输出中可以很容易计算出种子值。因此可以预测出下一个输出的随机数。
在注重信息安全的应用中,不要使用 LCG 算法生成随机数,请使用 SecureRandom。
Random类提供的方法:API
- nextBoolean() - 返回均匀分布的 true 或者 false
- nextBytes(byte[] bytes)
- nextDouble() - 返回 0.0 到 1.0 之间的均匀分布的 double
- nextFloat() - 返回 0.0 到1.0 之间的均匀分布的 float
- nextGaussian()- 返回 0.0 到 1.0 之间的高斯分布(即正态分布)的 double
- nextInt() - 返回均匀分布的 int
- nextInt(int n) - 返回 0 到 n 之间的均匀分布的 int(包括 0,不包括 n)
- nextLong() - 返回均匀分布的 long
- setSeed(long seed) - 设置种子
java.util.Random类有两种方式构建方式:
- 带种子
- 不带种子(类默认使用当前系统时钟作为种子)
只要种子一样,产生的随机数也一样: 因为种子确定,随机数算法也确定,因此输出是确定的。
Java 8 引入了新的 ints 方法,返回一个java.util.stream.IntStream
不带参数的 ints方法将返回一个无限 int 流:
IntStream unlimitedIntStream = random.ints();
调用时还可以指定参数来限制流大小:
IntStream limitedIntStream = random.ints(streamSize);
当然,也可以为生成数值设置最大值和最小值:
IntStream limitedIntStreamWithinARange = random.ints(streamSize, min, max);
3. java.util.concurrent.ThreadLocalRandom工具类
ThreadLocalRandom 是 JDK 7 之后提供,也是继承至 java.util.Random。
每一个线程有一个独立的随机数生成器,用于并发产生随机数,能够解决多个线程发生的竞争争夺。效率更高!
ThreadLocalRandom 不是直接用 new 实例化,而是第一次使用其静态方法 current() 得到ThreadLocal 实例,然后调用 java.util.Random 类提供的方法获得各种随机数。
public class JavaRandom {
public static void main(String args[]) {
new MyThread().start();
new MyThread().start();
}
}
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 2; i++) {
System.out.println(Thread.currentThread().getName() + ": " + ThreadLocalRandom.current().nextDouble());
}
}
}
4. java.util.SplittableRandom
Java 8 还带来了一个快速随机数生成器SplittableRandom类。
正如 JavaDoc 中描述的那样,这是一个支持并行计算的随机数生成器。值得注意的是,这个实例非线程安全。使用该类时需要当心。
现在有了 nextInt 和 ints 方法。调用 nextInt 时,可以通过参数指定 top 和 bottom 范围:
SplittableRandom splittableRandom = new SplittableRandom();
int randomWithSplittableRandom = splittableRandom.nextInt(min, max);
这里也提供了ints方法。这意味着可以轻松得到 int流。
5. java.Security.SecureRandom
此类提供强加密生成器(RNG),也是继承至 java.util.Random。操作系统收集了一些随机事件,比如鼠标点击,键盘点击等等,SecureRandom 使用这些随机事件作为种子。
强加密:
根据rfc 1750 描述:任何传递给secureRandom对象的种子材料必须是不可预知的,所有SecureRandom对象输出的输出序列必须是强加密的。
对象获取:
可通过无参构造或getInstance()方法获得对象
方法:
- generateSeed(int size);返回给定的种子字节数量
- getAlgorithm();返回算法名称
- getInstance();返回实现指定随机数生成器 (RNG) 算法的 SecureRandom 对象。此方法有多个重载方法
- getProvider();返回算法实现的提供商
- getSeed();返回给定的种子字节数量
- next();生成一个包含用户指定伪随机位数的整数(右对齐,带前导零)。
- nextBytes();生成用户指定的随机字节数
- setSeed();重新设置此随机对象的种子,有重载方法
支持的随机算法只有一个: SHA1PRNG
使用:
SecureRandom random1 = SecureRandom.getInstance("SHA1PRNG");
SecureRandom random2 = SecureRandom.getInstance("SHA1PRNG");
for (int i = 0; i < 5; i++) {
System.out.println(random1.nextInt() + " != " + random2.nextInt());
}
6. 随机字符串
可以使用 Apache Commons-Lang 包中的 RandomStringUtils 类。