Java 生成随机数的 5 种方式

本文探讨了Java中生成随机数的五种方式,包括Math.random()静态方法、java.util.Random、java.util.concurrent.ThreadLocalRandom、java.Security.SecureRandom以及随机字符串的生成。分析了它们的性能、线程安全性和适用场景,特别指出ThreadLocalRandom在多线程环境中的高效表现以及SecureRandom在加密安全性上的优势。
摘要由CSDN通过智能技术生成

先说结论

试测数据:

  • 基于常见场景:在一个数据范围区间内生成随机数。
  • 1000万的随机数范围,for循环生成50万个随机数。无其他额外操作。
SDK包 性能耗时 评价
java.util.Random 9毫秒 1、编写简单,方法较多,也快速。很多SDK包都基于此扩展。
2、随机性重度依赖seed的情况,seed一样,分配的随机数和顺序一样。
3、线程不安全。
ThreadLocalRandom 8毫秒 1、继承于java.util.Random
2、与线程绑定,一个线程一个,多线程下安全。
3、seed情况部分借助于线程的内存地址等随机信息,来提升随机性。
Math.Random 14毫秒 1、用法上比较费劲,只能生成double。
2、内部有借用java.util.Random
SecureRandom 142毫秒 线程安全,seed不可预测(借助于系统中的随机事件信息)
Apache#RandomDataGenerator 54毫秒 API比较丰富,特殊场景下考虑。
it.unimi.dsi#XoRoShiRo128PlusRandom 17毫秒 偏门的三方包。比较快。线程不安全。

1. Math.random() 静态方法

产生的随机数是 0 - 1 之间的一个 double,即 0 <= random <= 1

使用:

for (int i = 0; i < 10; i++) {
   
  System.out.println(Math.random());
}

结果:

0.3598613895606426 
0.2666778145365811 
0.25090731064243355 
0.011064998061666276 
0.600686228175639 
0.9084006027629496 
0.12700524654847833 
0.6084605849069343 
0.7290804782514261 
0.9923831908303121

实现原理:

When this method is first called, it creates a single new pseudorandom-number generator, exactly as if by the expression new java.util.Random() This new pseudorandom-number generator is used thereafter for all calls to this method and is used nowhere else.

当第一次调用 Math.random() 方法时,自动创建了一个伪随机数生成器,实际上用的是 new java.util.Random()。当接下来继续调用 Math.random() 方法时,就会使用这个新的伪随机数生成器。

源码如下:

public static double random() {
   
    Random rnd = randomNumberGenerator;
    if (rnd == null) rnd = initRNG(); // 第一次调用,创建一个伪随机数生成器
    return rnd.nextDouble();
}

private static synchronized Random initRNG() {
   
    Random rnd = randomNumberGenerator;
    return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd; // 实际上用的是new java.util.Random()
}

initRNG() 方法是 synchronized 的,因此在多线程情况下,只有一个线程会负责创建伪随机数生成器(使用当前时间作为种子),其他线程则利用该伪随机数生成器产生随机数。Java生成随机数的几种高级用法,这篇推荐看一下。

因此 Math.random() 方法是线程安全的


什么情况下随机数的生成线程不安全?

  • 线程1在第一次调用 random() 时产生一个生成器 generator1,使用当前时间作为种子。
  • 线程2在第一次调用 random() 时产生一个生成器 generator2,使用当前时间作为种子。
  • 碰巧 generator1 和 generator2 使用相同的种子,导致 generator1 以后产生的随机数每次都和 generator2 以后产生的随机数相同。

什么情况下随机数的生成线程安全?: Math.random() 静态方法使用

  • 线程1在第一次调用 random() 时产生一个生成器 generator1,使用当前时间作为种子。
  • 线程2在第一次调用 random() 时发现已经有一个生成器 generator1,则直接使用生成器 generator1。
public class JavaRandom {
   
    public static void main(String args
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值