java random 并发安全,关于多线程:并发使用java.util.Random时的争用

Oracle Java Documentation says:

Instances of java.util.Random are threadsafe. However, the concurrent use of the same java.util.Random instance across threads may encounter contention and consequent poor performance. Consider instead using ThreadLocalRandom in multithreaded designs.

穷人表现背后的原因是什么?

大概是因为内部状态有某种同步?

在内部,java.util.random使用当前种子保持原子长度,并且每当请求一个新的随机数时,在更新种子时就会发生争用。

从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会更频繁地失败。

随机类围绕内部状态持有一个同步锁,这样只有一个线程可以一次访问它——具体来说,它使用AtomicLong。这意味着,如果试图用多个线程从中读取,那么只有一个线程可以同时访问它,从而导致其他线程等待直到释放锁。

可以使用ThreadLocalRandom来提供每个线程实例的透明性,以确保在每个线程的基础上更新内部状态,从而避免锁定。

请注意,如果正确实现,除非运行大量线程,否则AtomicLong更新操作不应执行得很糟糕,因为它基本上可以在JVM中优化为类似于x86上的lock xchg之类的操作。锁之外的主要计算成本可能是长乘法和旋转移位的组合。

这不对。多个线程可以同时访问一个atomiclong。访问没有锁定。同时存在的原子使用挥发物。

不正确,Random遭受争用的原因是AtomicLong.compareAndSet,如果与多个线程一起使用,它本身就会受到争用。请参阅stackoverflow.com/questions/3556283/…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值