不要使用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