不要使用Math.random。它依赖于使用AtomicLong的全局实例java.util.Random
。尽管java.util.Random
中使用的PRNG算法是pretty simple,但性能主要受原子CAS和相关缓存一致性流量的影响。
对于多线程应用程序(如this example),这可能特别糟糕,但即使在单线程情况下也有惩罚。
ThreadLocalRandom总是优于Math.random。它不依赖于原子操作,也不会遭受争用。它只更新thread-local state并使用一对arithmetic and bitwise operations。
这是一个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()给你一个随机位置。所以“有点”,甚至是不会发生的每一次......如果你想有一个一致的输出(均匀分布)\你应该创建自己的操作... – DarkV1
只需基准!它的速度比添加的要慢,但速度足够快,可以多次采样。如果您需要一个以上的随机样本,则一次调用这些样本会更快(例如,创建一个随机池)。我不知道你在做什么,但我怀疑这里有更多的算法问题。例如:很难实现正确的随机播放。 – sascha
生成一个随机值(通过Math.random)是一个相当常见的操作,如果没有很好的理由,也不应该担心。它看起来像不成熟的优化。你有什么其他的方法? – zoom