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()
}

This method is properly synchronized to allow correct use by more than one thread. However, if many threads need to generate pseudorandom numbers at a great rate, it may reduce contention for each thread to have its own pseudorandom-number generator.

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

因此 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[]) {
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() + ": " + Math.random());
}
}
}

结果:

Thread-1: 0.8043581595645333
Thread-0: 0.9338269554390357
Thread-1: 0.5571569413128877
Thread-0: 0.37484586843392464

2. java.util.Random 工具类

基本算法:linear congruential pseudorandom number generator (LGC) 线性同余法伪随机数生成器
缺点:可预测

An attacker will simply compute the seed from the output values observed. This takes significantly less time than 2^48 in the case of java.util.Random.
从输出中可以很容易计算出种子值。
It is shown that you can predict future Random outputs observing only two(!) output values in time roughly 2^16.
因此可以预测出下一个输出的随机数。
You should never use an LCG for security-critical purposes.
在注重信息安全的应用中,不要使用 LCG 算法生成随机数,请使用 SecureRandom。

使用:

Random random = new Random();

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

结果:

-24520987
-96094681
-952622427
300260419
1489256498

Random类默认使用当前系统时钟作为种子:

public Random() {
this(seedUniquifier() ^ System.nanoTime());
} public Random(long seed) {
if (getClass() == Random.class)
this.seed = new AtomicLong(initialScramble(seed));
else {
// subclass might have overriden setSeed
this.seed = new AtomicLong();
setSeed(seed);
}
}

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) - 设置种子

只要种子一样,产生的随机数也一样: 因为种子确定,随机数算法也确定,因此输出是确定的!

Random random1 = new Random(10000);
Random random2 = new Random(10000); for (int i = 0; i < 5; i++) {
System.out.println(random1.nextInt() + " = " + random2.nextInt());
}

结果:

-498702880 = -498702880
-858606152 = -858606152
1942818232 = 1942818232
-1044940345 = -1044940345
1588429001 = 1588429001

3. java.util.concurrent.ThreadLocalRandom 工具类

ThreadLocalRandom 是 JDK 7 之后提供,也是继承至 java.util.Random。

private static final ThreadLocal<ThreadLocalRandom> localRandom =
new ThreadLocal<ThreadLocalRandom>() {
protected ThreadLocalRandom initialValue() {
return new ThreadLocalRandom();
}
};

每一个线程有一个独立的随机数生成器,用于并发产生随机数,能够解决多个线程发生的竞争争夺。效率更高!
ThreadLocalRandom 不是直接用 new 实例化,而是第一次使用其静态方法 current() 得到 ThreadLocal<ThreadLocalRandom> 实例,然后调用 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());
}
}
}

结果:

Thread-0: 0.13267085355389086
Thread-1: 0.1138484950410098
Thread-0: 0.17187774671469858
Thread-1: 0.9305225910262372

4. java.Security.SecureRandom

也是继承至 java.util.Random。

Instances of java.util.Random are not cryptographically secure. Consider instead using SecureRandom to get a cryptographically secure pseudo-random number generator for use by security-sensitive applications.
SecureRandom takes Random Data from your os (they can be interval between keystrokes etc - most os collect these data store them in files - /dev/random and /dev/urandom in case of linux/solaris) and uses that as the seed.
操作系统收集了一些随机事件,比如鼠标点击,键盘点击等等,SecureRandom 使用这些随机事件作为种子。

SecureRandom 提供加密的强随机数生成器 (RNG),要求种子必须是不可预知的,产生非确定性输出。
SecureRandom 也提供了与实现无关的算法,因此,调用方(应用程序代码)会请求特定的 RNG 算法并将它传回到该算法的 SecureRandom 对象中。

  • 如果仅指定算法名称,如下所示:
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG");

  • 如果既指定了算法名称又指定了包提供程序,如下所示:
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");

使用:

SecureRandom random1 = SecureRandom.getInstance("SHA1PRNG");
SecureRandom random2 = SecureRandom.getInstance("SHA1PRNG"); for (int i = 0; i < 5; i++) {
System.out.println(random1.nextInt() + " != " + random2.nextInt());
}

结果:

704046703 != 2117229935
60819811 != 107252259
425075610 != -295395347
682299589 != -1637998900
-1147654329 != 1418666937

5. 随机字符串

可以使用 Apache Commons-Lang 包中的 RandomStringUtils 类。
Maven 依赖如下:

<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>

API 参考:https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/RandomStringUtils.html

示例:

public class RandomStringDemo {
public static void main(String[] args) {
// Creates a 64 chars length random string of number.
String result = RandomStringUtils.random(64, false, true);
System.out.println("random = " + result); // Creates a 64 chars length of random alphabetic string.
result = RandomStringUtils.randomAlphabetic(64);
System.out.println("random = " + result); // Creates a 32 chars length of random ascii string.
result = RandomStringUtils.randomAscii(32);
System.out.println("random = " + result); // Creates a 32 chars length of string from the defined array of
// characters including numeric and alphabetic characters.
result = RandomStringUtils.random(32, 0, 20, true, true, "qw32rfHIJk9iQ8Ud7h0X".toCharArray());
System.out.println("random = " + result); }
}

RandomStringUtils 类的实现上也是依赖了 java.util.Random 工具类:

 
RandomStringUtils 类的定义

引用:
http://yangzb.iteye.com/blog/325264
Difference between java.util.Random and java.security.SecureRandom

 
 

Java 随机数 Random VS SecureRandom的更多相关文章

  1. 真伪随机数 ——Random和SecureRandom

    Random Random用来创建伪随机数.所谓伪随机数,是指只要给定一个初始的种子,产生的随机数序列是完全一样的. 要生成一个随机数,可以使用nextInt().nextLong().nextFlo ...

  2. 实现java随机数Random的几招

    一,在java.util这个包里面提供了一个Random的类,我们可以新建一个Random的对象来产生随机数,可以产生随机整数.随机float.随机double,随机long,这个也是我们经常用的一个 ...

  3. 随机数Random和SecureRandom

    "Random" objects should be reused Bug Critical Main sources owasp-a6 Available SinceNov 16 ...

  4. Java如何生成随机数 - Random、ThreadLocalRandom、SecureRandom

    Java7 的Random伪随机数和线程安全的ThreadLocalRandom 一.Random伪随机数: Random 类专门用于生成一个伪随机数,它有两个构造器: 一个构造器使用默认的种子(以当 ...

  5. java java.uitl.Random产生随机数

    通过使用java.uitl.Random产生一个1-10内的随机数.例: Random random = new Random(); int i = Math.abs(random.nextInt() ...

  6. Java – Generate random integers in a rangejava获取某个范围内的一个随机数

    In this article, we will show you three ways to generate random integers in a range. java.util.Rando ...

  7. java的random生成某个范围内的随机数

    import java.util.Random; /** * @author HP * @date 2019/4/16 */ public class randomTest { public stat ...

  8. Java随机数

    本章先讲解Java随机数的几种产生方式,然后通过示例对其进行演示. 广义上讲,Java中的随机数的有三种产生方式:(01). 通过System.currentTimeMillis()来获取一个当前时间 ...

  9. 硬核 - Java 随机数相关 API 的演进与思考(上)

    本系列将 Java 17 之前的随机数 API 以及 Java 17 之后的统一 API 都做了比较详细的说明,并且将随机数的特性以及实现思路也做了一些简单的分析,帮助大家明白为何会有这么多的随机数算 ...

  10. 硬核 - Java 随机数相关 API 的演进与思考(下)

    本系列将 Java 17 之前的随机数 API 以及 Java 17 之后的统一 API 都做了比较详细的说明,并且将随机数的特性以及实现思路也做了一些简单的分析,帮助大家明白为何会有这么多的随机数算 ...

随机推荐

  1. 封装一个Promise.all 的函数

    // 1. 准备三个异步函数 const promise1 = Promise.resolve('prom11ise1'); const promise2 = new Promise(function ...

  2. OGRE 渲染引擎 Windows 平台构建及编译

    0 OGRE 机器人领域常见的Rviz和Gazebo可视化的渲染后端. 1 无数的坑 这东西真的可恶,官方教程文档以及项目构建的方式是真的繁琐,在Windows上. CMake 的构建必须要使用 CM ...

  3. Web渗透09_文件包含漏洞

    1 文件包含漏洞描述 开发人员编写代码时独立性好是一个很重要的要求,这边一个数据库类,那边一个模型类.几百行的整体代码,在整合时两行行代码就可以包含进来使用.文件包含有助于独立的代码之间的配合!有时引 ...

  4. hadoop运行原理

    包括HDFS和Mapreduce两部分. 1)HDFS自动保存多个副本,移动计算.缺点是小文件存取占用namenode内存,写入只支持追加,不能随机修改. 它存储的逻辑空间称为block,文件的权限类 ...

  5. [python]Gunicorn加持,轻松提升Flask超7倍性能

    前言 之前学习和实际生产环境的flask都是用app.run()的默认方式启动的,因为只是公司内部服务,请求量不高,一直也没出过什么性能问题.最近接管其它小组的服务时,发现他们的服务使用Gunicor ...

  6. 什么是AOP面向切面编程?怎么简单理解?

    本文原文地址:什么是AOP面向切面编程?怎么简单理解? 什么是AOP面向切面编程 面向切面编程(AOP)通过将横切关注点(cross-cutting concerns)分离出来,提供了一种增强代码模块 ...

  7. 2.16 Linux挂载详解

    前面讲过,Linux 系统中"一切皆文件",所有文件都放置在以根目录为树根的树形目录结构中.在 Linux 看来,任何硬件设备也都是文件,它们各有自己的一套文件系统(文件目录结构) ...

  8. Python如何获取request response body

    在Python中,我们可以使用多个库来发送HTTP请求并获取响应体(response body).其中,最常用的库之一是 requests.这个库提供了简单易用的接口来发送HTTP请求,并可以方便地获 ...

  9. delphi12 Android Edit SDK安装

    安装 delphi 12.1 后,编译 FMX Android 程序失败! 查找原因,SDK配置全是叹号! 之前用过SDK Manager.exe,直接打开即可以选择下载,但现在发现没有了,查找资料如 ...

  10. 记录个Java/Groovy的小问题:空字符串调用split函数返回非空数组

    问题复现 最近写了一个groovy替换程序增量流水线脚本(会Java也能看懂),示意脚本如下: //获取文件列表方法 def listFiles(folder) { def output = sh(s ...