Random类生成伪随机数流,Random类使用 48 位种子
Random的实例是线程安全的,但Random在并发中使用性能较差,可以在并发环境中使用ThreadLocalRandom
Random的实例在密码学上不是安全的,们可以使用SecureRandom来获得加密安全的伪随机数
Math.random()用于在更简单的用例中获取伪随机数
注意:使用Random只得到伪随机数而不是实际随机数。伪随机数是使用确定性过程生成的,它们在统计上近似是随机的
Random有两种构造方法:
Random():创建一个新的随机数生成器Random(long seed):使用单个 long 种子创建一个新的随机数生成器下面介绍Random的方法
doubles():返回伪随机 double 的流ints():返回伪随机 int 的流longs():返回伪随机 long 的流上面三个方法均有三个可选参数:streamSize,randomNumberOrigin,randomNumberBound
例如:random.doubles(5, 0, 10)表示返回 5 个范围在[0, 10)的随机数;注意:范围区间是「前闭后开」
再介绍一些其他方法
nextBoolean():返回下一个伪随机 boolean 值nextBytes(byte[] bytes):生成随机字节nextDouble():返回 0.0 到 1.0 之间的下一个伪随机 double 值nextFloat():返回 0.0 到 1.0 之间的下一个伪随机 float 值nextGaussian():返回下一个伪随机、高斯分布 double 值,均值为 0.0,标准差为 1.0nextInt():返回下一个伪随机 int 值nextLong()返回下一个伪随机 long 值setSeed():设置随机数生成器的种子注意:
nextDouble()和nextFloat()返回的都是[0.0, 1.0)范围内的一个值;注意:范围区间是「前闭后开」nextInt()和nextLong()分别返回一个 32 位和 64 位的值nextInt(int bound)返回一个[0, bound)范围内的一个值;注意:范围区间是「前闭后开」下面给出几个例子:
xRandom random = new Random();
// random.doubles(streamSize, randomNumberOrigin, randomNumberBound) 方法的应用例子double[] rd = random.doubles(5, 0, 10).toArray();
// nextBytes(byte[] bytes) 方法的应用例子byte[] bytes = new byte[5];random.nextBytes(bytes);System.out.println(Arrays.toString(bytes));
// nextDouble() 方法的应用例子// 结果:0.35761840335259487random.nextDouble();
// nextInt() 方法的应用例子// 结果:871207694random.nextInt();
// nextInt(bound)// 结果:3random.nextInt(5)先看一个例子:
xxxxxxxxxxRandom ran1 = new Random(10);System.out.println("使用种子为 10 的 Random 对象生成 [0,10) 内随机整数序列: ");for (int i = 0; i < 10; i++) { System.out.print(ran1.nextInt(10) + " ");}System.out.println();Random ran2 = new Random(10);System.out.println("使用另一个种子为 10 的 Random 对象生成 [0,10) 内随机整数序列: ");for (int i = 0; i < 10; i++) { System.out.print(ran2.nextInt(10) + " ");}输出结果:
xxxxxxxxxx使用种子为 10 的 Random 对象生成 [0,10) 内随机整数序列:3 0 3 0 6 6 7 8 1 4使用另一个种子为 10 的 Random 对象生成 [0,10) 内随机整数序列:3 0 3 0 6 6 7 8 1 4
不难发现生成的两组 10 个随机数都是一样的,这是因为我们使用了相同的随机种子
对于种子相同的Random对象,生成的随机数序列是一样的
在没带参数构造函数生成的 Random 对象的种子缺省是「当前系统时间的毫秒数」
所以在高并发下,每个用户线程生成随机数时,可能出现「系统时间的毫秒数」相同的情况
如果这个时候我们并没有自定义随机种子,极有可能出现多个用户生成的随机数相同的情况
具体可以看下面这个例子:
xxxxxxxxxxpublic class MyThread { private static final int[] cnt = new int[1000000000];
private static void createThread() { new Thread(() -> { // 创建 100 个 funThread 线程 for (int i = 0; i < 100; i++) { funThread(); } }).start(); }
private static void funThread() { new Thread(MyThread::testMethod).start(); }
private static void testMethod() { Random random = new Random(); cnt[random.nextInt(1000000000)]++; }
public static void main(String[] args) throws InterruptedException { // 创建 100 个线程 for (int i = 0; i < 1000; i++) { createThread(); } Thread.sleep(10000); for (int i = 0; i < 1000000000; i++) { if (cnt[i] > 1) { System.out.println(i + "_" + cnt[i]); } } }}Math.random()返回[0.0, 1.0)正伪随机 double 值,和random.nextDouble();功能等价