java.util.Random的实例是线程安全的。然而,在跨线程使用同一java.util.Random实例的并发情况下,可能会遇到争用和随之而来的性能不佳。在多线程设计中,考虑改用ThreadLocalRandom。
性能不佳的原因是什么?
java.util.Random的实例是线程安全的。然而,在跨线程使用同一java.util.Random实例的并发情况下,可能会遇到争用和随之而来的性能不佳。在多线程设计中,考虑改用ThreadLocalRandom。
性能不佳的原因是什么?
在内部,java.util.Random使用AtomicLong保持当前种子,每当请求一个新的随机数时,更新种子会产生竞争。
来自java.util.Random的实现:
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
另一方面,ThreadLocalRandom 通过为每个线程提供一个种子,确保在没有竞争的情况下更新种子。
next
,则性能不佳只会发生,因为如果更多的线程同时调用next
,compareAndSet
将更容易失败。 - TwoTheAtomicLong.compareAndSet
,如果与许多线程一起使用,它本身也会遭受争用。请参考https://dev59.com/tHA65IYBdhLWcg3w7TWZ。 - Nearoo