Java 与简单算术运算相比,Math.random()运行所需的时间是多少?

Java 与简单算术运算相比,Math.random()运行所需的时间是多少?,java,performance,random,Java,Performance,Random,在Java中,相对于一个简单的算术运算,Math.random()生成一个数字需要多长时间?我尝试在已经包含值的ArrayList中随机分布对象,这样会创建一个稍微均匀但不完全均匀的分布,并且我不确定是否使用Math.random()为每个插入点选择一个随机索引是最好的方法 澄清:插入对象的分布应足够均匀,使值不会全部集中在一个区域,但也应足够不均匀,使分布不可预测(如果有人一个接一个地检查这些值,他们将无法通过检测常量模式来确定下一个值是否是新插入的值)。Java文档将此报告为实现,这就是Ma

在Java中,相对于一个简单的算术运算,Math.random()生成一个数字需要多长时间?我尝试在已经包含值的ArrayList中随机分布对象,这样会创建一个稍微均匀但不完全均匀的分布,并且我不确定是否使用Math.random()为每个插入点选择一个随机索引是最好的方法


澄清:插入对象的分布应足够均匀,使值不会全部集中在一个区域,但也应足够不均匀,使分布不可预测(如果有人一个接一个地检查这些值,他们将无法通过检测常量模式来确定下一个值是否是新插入的值)。

Java文档将此报告为实现,这就是
Math.random()
最终调用的

 public double nextDouble() {
   return (((long)next(26) << 27) + next(27))
     / (double)(1L << 53);
 }
public double nextDouble(){
返回(((长)下一个(26)(48位))


正如您所看到的,它使用一个简单的算法来生成伪随机值。它只需要一些廉价的操作,因此我不会担心使用它。

创建一个随机数是一个简单的操作,您不应该担心它

但是你应该记住几件事

  • 最好重用随机实例,每次需要随机值时创建
    新的Random()
    实例通常是一个错误的决定

  • 但是,不要同时跨多个线程使用同一个随机实例来避免争用,您可以使用

  • 如果你真的这样做了,请改用


不要使用Math.random。它依赖于在引擎盖下使用的
java.util.random
的全局实例。虽然
java.util.random
中使用的PRNG算法是,但性能主要受原子CA和相关缓存一致性流量的影响

这对于多线程应用程序(如中)来说可能特别糟糕,但即使在单线程情况下也会受到惩罚

总是比Math.random更可取。它不依赖于原子操作,也不受争用的影响。它只更新一个,并使用两个

下面是一个JMH基准测试,用于将
Math.random()
ThreadLocalRandom.current().nextDouble()
的性能与一个简单的算术运算进行比较

package bench;

import org.openjdk.jmh.annotations.*;
import java.util.concurrent.ThreadLocalRandom;

@State(Scope.Thread)
public class RandomBench {
    double x = 1;

    @Benchmark
    public double multiply() {
        return x * Math.PI;
    }

    @Benchmark
    public double mathRandom() {
        return Math.random();
    }

    @Benchmark
    public double threadLocalRandom() {
        return ThreadLocalRandom.current().nextDouble();
    }
}
结果表明,ThreadLocalRandom的工作时间仅为几纳秒,其性能与简单的算术运算相当,并且与Math.random不同,它可以在多线程环境中完美地扩展

Benchmark                      Threads     Score     Error  Units
RandomBench.mathRandom            1       34.265 ±   1.709  ns/op
RandomBench.multiply              1        4.531 ±   0.108  ns/op
RandomBench.threadLocalRandom     1        8.322 ±   0.047  ns/op

RandomBench.mathRandom            2      366.589 ±  63.899  ns/op
RandomBench.multiply              2        4.627 ±   0.118  ns/op
RandomBench.threadLocalRandom     2        8.342 ±   0.079  ns/op

RandomBench.mathRandom            4     1328.472 ± 177.216  ns/op
RandomBench.multiply              4        4.592 ±   0.091  ns/op
RandomBench.threadLocalRandom     4        8.474 ±   0.157  ns/op

Math.random()为您提供了一个随机位置。因此,如果您想要一致的输出(均匀分布),那么“有些”甚至不会每次都发生\您应该创建自己的操作…只需对其进行基准测试!它比一次添加慢得多,但速度足够快,可以多次采样。如果您需要一个以上的随机采样,则可以一次调用所有这些操作(例如,创建随机池).我不知道你在做什么,但我怀疑这里有更多的算法问题。例如:很难实现正确的洗牌。生成随机值(通过Math.random)这是一个相当常见的操作,你也不必担心它,也没有很好的理由。它看起来像是过早的优化。你认为其他的方法是什么?在这种情况下随机是你最好的选择……虽然总是有一个机会,它不是均匀分布的。你可以用一个条件来控制它来重新滚动一个不同的索引。如果它太靠近其他索引,除非你想洗去数以百万计的问题,这不是性能关键。考虑到在鼠标点击的声波从鼠标到点击按钮的人的耳朵的时候,计算机可以创造成千上万(如果不是百万)。关于随机数。不管怎样:我建议根本不要使用
Math.random()
。在大多数情况下,专用的
random
实例更通用(也更容易调试)。虽然该算法非常简单,但其性能受性能影响,即使在单线程应用程序中,性能也会受到影响,更不用说在多线程情况下可能存在的争用了。