【java】java 随机数 Random ThreadLocalRandom SecureRandom

在这里插入图片描述

1.概述

出自:《java性能权威指南》

Java 7 提 供 了 3 个 标 准 的 随 机 数 生 成 器 类:java.util.Random、 java.util.concurrent.ThreadLocalRandom 以及java.security.SecureRandom。这三个类在性能方面差距很大。

2. Random 和 ThreadLocalRandom区别

Random 和 ThreadLocalRandom 两个类的差别是, Random 类的主要操作( nextGaussian())是同步的。任何要获取随机值的方法都会用到这个方法,所以不管如何使用该随机数生成器,都会存在锁竞争:如果两个线程同时使用同一随机数生成器, 那一个线程要等待另一个先完成其操作。之所以会使用 ThreadLocalRandom,原因就在于此:每个线程都有自己的
随机数生成器, Random 类的同步就不是问题了。(正如第 7 章所讨论的,因为创建对象成本很高,而 ThreadLocalRandom 类会重用对象,所以有很大的性能优势。)

3.SecureRandom区别

SecureRandom 类与上面介绍的两个类的区别是,所用的算法不同。 Random 类(以及继承它而来的 ThreadLocalRandom)实现了一个典型的伪随机数算法。尽管那些算法非常复杂,但到底是确定性的。如果知道初始种子,很容易确定该引擎将生成的数字的精确序列。这意
味着,黑客能够从特定的生成器看到数字序列,也就能够指出下一个数字是什么。尽管好的伪随机数生成器可以生成看上去真正随机的数字序列(甚至符合随机性的概率期望),但这仍然不是真正的随机。

而另一方面, SecureRandom 类使用一个系统接口来获得随机数。数据生成方式与所用的操作系统有关,不过一般而言,这类源 2 提供了基于真正随机事件(比如鼠标移动时)的数据。这就是所谓的基于熵的随机性,比依赖随机数的操作更安全。 SSL 熵是这类操作中最广为人知的例子:加密所用的随机数不可能通过基于熵的源来确定(即便在算法中使用了 SecureRandom 随机数生成器,还是有其他方式可以攻破数据的加密算法。)

遗憾的是,计算机生成的熵的数量是有限的,所以要从一个安全随机数生成器获得大量的随机数,需要很长时间。调用 SecureRandom 类的 nextRandom() 方法消耗的时间并不确定,跟系统中还有多少熵尚未使用有关。如果没有熵可用,这个调用看上去就挂起了,可能一次长达
数秒,直到有可用的熵为止。所以对性能的计时非常困难,因为性能本身也是随机的。对于会创建很多 SSL 连接,或者需要大量安全随机数的应用而言,这往往会成为问题;这样的应用要花很多时间去执行其操作。当在一个这样的应用上执行性能测试时,请注意,计时会有很多变数。除了像第 2 章讨论的那样运行大量示例测试,其实没什么办法处理此类变数。另一种选择是联系操作系统厂商,看他们是不是有更多(或更好的)基于熵的源。

必要时,可以使用第 3 种选择,即使用 Random 类运行性能测试,即便在生产环境中使用的是 SecureRandom 类。 如果性能测试是模块级的,这会很有意义:在同样的一段时间内,与产品系统相比,这些测试需要的随机数更多(比如需要更多 SSL 套接字)。但是,最终预期的负载必须用 SecureRandom 类来测试,以确定生产系统上的负载是否能够获得足够的随机数。

4.快速小结

  1. Java 默认的 Random 类的初始化的成本很高,但是一旦初始化完毕,就可以重用。
  2. 在多线程代码中,应该首选 ThreadLocalRandom 类。
  3. SecureRandom 类表现出的性能也是随意的和完全随机的。在对用到这个类的代码做性能测试时,一定要认真规划

猜你喜欢

转载自blog.csdn.net/qq_21383435/article/details/115027415