Java随机数怎么生成

在Java中,我们可以使用多种方法来生成随机数。以下是其中几种常见的方法:

1.使用Random类生成随机数Random类是Java中用于生成随机数的标准类。可以使用它的nextInt()和nextDouble()等方法来生成随机整数和随机浮点数。例如:

2.使用Math.random()生成随机数Math.random()方法可以生成一个0到1之间的随机浮点数。例如

3.使用ThreadLocalRandom类生成随机数ThreadLocalRandom类是Java中用于生成随机数的线程安全类。可以使用它的nextInt()和nextDouble()等方法来生成随机整数和随机浮点数。例如:

这些方法都可以用来生成随机数,具体使用哪种方法取决于具体情况和需要。需要注意的是,生成的随机数并不是真正的随机数,而是伪随机数,它们是通过一定的算法生成的,因此在某些情况下可能会出现重复的情况。

软网推荐:Windows环境下快速生成随机数

日常工作中,需要使用随机数的场合很多。做实验时,可能需要一些随机数来作测试;不少产品商家需要给产品配上随机序列号,或给VIP用户卡分配随机卡号。那么,在Windows环境下,如何才能自动生成满足需要的随机数呢?

1. 特定区间普通随机数的生成

如果在进行实验时,需要生成一个特定区间内的随机数,首先可以通过我们所熟悉的Excel软件来创建。主要利用RAND和RANDBETWEEN两个函数来实现。

例如,需要生成0到1区间内的随机数,可使用函数“=RAND()”来实现;要生成0到10之间的随机数,可使用函数表达式“=RAND()*10”;若需要1到10之间的随机数,要用表达式“RAND()*(10-1)+1”。同样地,若需要0到100之间的随机数,使用“RAND()*100”函数表达式;1到100之间的随机数,使用“RAND()*(100-1)+2”函数表达式(图1)。

我们注意到,上述随机数都是小数。那么,如果要生成整数怎么办呢?有两种办法,一个是对生成的小数随机数取整,一个是直接生成整数随机数。第一种例如在表达式“RAND()*(100-1)+2”的基础上外加TRUNC()函数,生成1到100之间的随机整数,整个表达式表述为“=TRUNC(RAND()*(100-1)+2)”;第二种则可以直接使用RANDBETWEEN()函数,用表达式“=RANDBETWEEN(0,10)”生成0到10之间的随机整数,表达式“=RANDBETWEEN(50,9999)”生成50到9999之间的随机整数(图2)。可见,RANDBETWEEN()函数用起来更形象,也更简单。

如果觉得上述方式生成区间随机数比较麻烦,可利用第三方工具软件实现。比如使用Random Number Generator,可以很方便地进行随机数区域设置和条件限定,从而自动生成满足条件的随机数。

软件运行后,在左侧上方Interval from后的两个框中输入随机数生成的范围值,在Digits after decimal point后输入截取的小数位,在Number of digits to generate后输入每次生成的随机数个数。之后,点击Generate integer按钮即可生成指定数量的随机整数,点击Generate decimal则生成相应的随机小数(图3)。

随机数的生成条件设置之后,建立随机数的操作还可以用快捷键来完成。按下功能键F1可以建立指定范围的整数,按下F2生成指定范围的小数,按下F4则清除随机数列表。如果要生成大量的随机数,要从中找到一个特定的随机数是否存在,可使用Find按钮进行查找,找到后自动定位到该随机数(图4)。若中途要停止随机数的生成,可按下Esc键。

小提示:如果要求生成不重复的随机数,请选择Next random number does not equal current复选框。如果要复制生成的某个随机数或随机数列表,用软件窗口左下角的几个按钮来操作即可。

2. 特定格式产品序列号的生成

作为产品生产商家的工作人员,要给自己的软硬件产品编排序列号,或者销售商要给客户VIP卡配置序列号,也可以用两种方法来实现。

首先,可以使用Excel的随机函数表达式。假设要生成形如“123-456”这样的由两段三位数字和连字符组成随机数序列号,可以使用“=RANDBETWEEN(100,999)& \” – \” &RANDBETWEEN(100,999)”函数表达式。其中的“&”符号连接前后结果,而“-”表示以指定连字符连接前后两段随机数。

依此类推,如果要生成由四段六位数字组成的随机序列号,可使用“=RANDBETWEEN(100000,999999)& \” – \” &RANDBETWEEN(100000,999999)& \” – \” && \” – \” &RANDBETWEEN(100000,999999)& \” – \” &RANDBETWEEN(100000,999999)& \” – \” &RANDBETWEEN(100000,999999)& \” – \” &RANDBETWEEN(100000,999999)”函数表达式(图5)。

序列号的生成还可以使用第三方专用工具,如Portable Abluescarab Software CD-Key Generator软件。首次使用该软件弹出提示,需要进行参数配置,配置参数主要有序列号的段数和每段的字符数两个参数(图6)。

进入序列号生成器的主窗口后,先通过下拉列表,在使用数字、字符、数字+字符3种方式中选择一种,再通过下面的复选框选择是否使用小写字母,然后点击Generate按钮,即可建立一组序列号(图7)。

小提示:虽然该软件为CD-Key而设计,但生成其他产品序列号同样适用。

Java中生成随机数的4种方式

在 Java 中,生成随机数的场景有很多,所以本文我们就来盘点一下 4 种生成随机数的方式,以及它们之间的区别和每种生成方式所对应的场景。

Random 类诞生于 JDK 1.0,它产生的随机数是伪随机数,也就是有规则的随机数。Random 使用的随机算法为 linear congruential pseudorandom number generator (LGC) 线性同余法伪随机数。在随机数生成时,随机算法的起源数字称为种子数(seed),在种子数的基础上进行一定的变换,从而产生需要的随机数字。

Random 对象在种子数相同的情况下,相同次数生成的随机数是相同的。比如两个种子数相同的 Random 对象,第一次生成的随机数字完全相同,第二次生成的随机数字也完全相同。默认情况下 new Random() 使用的是当前纳秒时间作为种子数的

使用 Random 生成一个从 0 到 10 的随机数(不包含 10),实现代码如下:

以上程序的执行结果为:

Random 使用 LGC 算法生成伪随机数的优点是执行效率比较高,生成的速度比较快

它的缺点是如果 Random 的随机种子一样的话,每次生成的随机数都是可预测的(都是一样的)。如下代码所示,当我们给两个线程设置相同的种子数的时候,会发现每次产生的随机数也是相同的:

以上程序的执行结果为:

当我们要使用一个类时,我们首先关心的第一个问题是:它是否为线程安全?对于 Random 来说,Random 是线程安全的

PS:线程安全指的是在多线程的场景下,程序的执行结果和预期的结果一致,就叫线程安全的,否则则为非线程安全的(也叫线程安全问题)。比如有两个线程,第一个线程执行 10 万次 ++ 操作,第二个线程执行 10 万次 — 操作,那么最终的结果应该是没加也没减,如果程序最终的结果和预期不符,则为非线程安全的。

我们来看 Random 的实现源码:

PS:本文所有源码来自于 JDK 1.8.0_211。

从以上源码可以看出,Random 底层使用的是 CAS(Compare and Swap,比较并替换)来解决线程安全问题的,因此对于绝大数随机数生成的场景,使用 Random 不乏为一种很好的选择。

PS:Java 并发机制实现原子操作有两种:一种是锁,一种是 CAS。

CAS 是 Compare And Swap(比较并替换)的缩写,java.util.concurrent.atomic 中的很多类,如(AtomicInteger AtomicBoolean AtomicLong等)都使用了 CAS 机制来实现。

ThreadLocalRandom 是 JDK 1.7 新提供的类,它属于 JUC(java.util.concurrent)下的一员,为什么有了 Random 之后还会再创建一个 ThreadLocalRandom?

原因很简单,通过上面 Random 的源码我们可以看出,Random 在生成随机数时使用的 CAS 来解决线程安全问题的,然而 CAS 在线程竞争比较激烈的场景中效率是非常低的,原因是 CAS 对比时老有其他的线程在修改原来的值,所以导致 CAS 对比失败,所以它要一直循环来尝试进行 CAS 操作。所以在多线程竞争比较激烈的场景可以使用 ThreadLocalRandom 来解决 Random 执行效率比较低的问题

当我们第一眼看到 ThreadLocalRandom 的时候,一定会联想到一次类 ThreadLocal,确实如此。ThreadLocalRandom 的实现原理与 ThreadLocal 类似,它相当于给每个线程一个自己的本地种子,从而就可以避免因多个线程竞争一个种子,而带来的额外性能开销了

接下来我们使用 ThreadLocalRandom 来生成一个 0 到 10 的随机数(不包含 10),实现代码如下:

以上程序的执行结果为:

ThreadLocalRandom 的实现原理和 ThreadLocal 类似,它是让每个线程持有自己的本地种子,该种子在生成随机数时候才会被初始化,实现源码如下:

ThreadLocalRandom 结合了 Random 和 ThreadLocal 类,并被隔离在当前线程中。因此它通过避免竞争操作种子数,从而在多线程运行的环境中实现了更好的性能,而且也保证了它的线程安全

另外,不同于 Random, ThreadLocalRandom 明确不支持设置随机种子。它重写了 Random 的

setSeed(long seed) 方法并直接抛出了 UnsupportedOperationException 异常,因此降低了多个线程出现随机数重复的可能性

源码如下:

只要程序中调用了 setSeed() 方法就会抛出 UnsupportedOperationException 异常,如下图所示:

虽然 ThreadLocalRandom 不支持手动设置随机种子的方法,但并不代表 ThreadLocalRandom 就是完美的,当我们查看 ThreadLocalRandom 初始化随机种子的方法 initialSeed() 源码时发现,默认情况下它的随机种子也是以当前时间有关,源码如下:

从上述源码可以看出,当我们设置了启动参数“-Djava.util.secureRandomSeed=true”时,ThreadLocalRandom 会产生一个随机种子,一定程度上能缓解随机种子相同所带来随机数可预测的问题,然而默认情况下如果不设置此参数,那么在多线程中就可以因为启动时间相同,而导致多个线程在每一步操作中都会生成相同的随机数

SecureRandom 继承自 Random,该类提供加密强随机数生成器。SecureRandom 不同于 Random,它收集了一些随机事件,比如鼠标点击,键盘点击等,SecureRandom 使用这些随机事件作为种子。这意味着,种子是不可预测的,而不像 Random 默认使用系统当前时间的毫秒数作为种子,从而避免了生成相同随机数的可能性。

以上程序的执行结果为:

SecureRandom 默认支持两种加密算法:

  1. SHA1PRNG 算法,提供者 sun.security.provider.SecureRandom;
  2. NativePRNG 算法,提供者 sun.security.provider.NativePRNG。

当然除了上述的操作方式之外,你还可以选择使用 new SecureRandom() 来创建 SecureRandom 对象,实现代码如下:

通过 new 初始化 SecureRandom,默认会使用 NativePRNG 算法来生成随机数,但是也可以配置 JVM 启动参数“-Djava.security”参数来修改生成随机数的算法,或选择使用 getInstance(\”算法名称\”) 的方式来指定生成随机数的算法。

Math 类诞生于 JDK 1.0,它里面包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数,当然它里面也包含了生成随机数的静态方法 Math.random() ,此方法会产生一个 0 到 1 的 double 值,如下代码所示。

以上程序的执行结果为:

当然如果你想用它来生成一个一定范围的 int 值也是可以的,你可以这样写:

以上程序的执行结果为:

通过分析 Math 的源码我们可以得知:当第一次调用 Math.random() 方法时,自动创建了一个伪随机数生成器,实际上用的是 new java.util.Random(),当下一次继续调用 Math.random() 方法时,就会使用这个新的伪随机数生成器。

源码如下:

本文我们介绍了 4 种生成随机数的方法,其中 Math 是对 Random 的封装,所以二者比较类似。Random 生成的是伪随机数,是以当前纳秒时间作为种子数的,并且在多线程竞争比较激烈的情况下因为要进行 CAS 操作,所以存在一定的性能问题,但对于绝大数应用场景来说,使用 Random 已经足够了。当在竞争比较激烈的场景下可以使用 ThreadLocalRandom 来替代 Random,但如果对安全性要求比较高的情况下,可以使用 SecureRandom 来生成随机数,因为 SecureRandom 会收集一些随机事件来作为随机种子,所以 SecureRandom 可以看作是生成真正随机数的一个工具类。

www.cnblogs.com/weink1215/p/4433790.html

blog.csdn.net/lycyingO/article/details/95276195

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。