1. 背景
在看同事写的代码的时候发现代码里有很多像:
如果我们想要生成一个随机数,通常会使用Random类。但是在并发情况下Random生成随机数的性能并不是很理想,今天给大家介绍一下JUC包中的用于生成随机数的类–ThreadLocalRandom.(本文基于JDK1.8)
当然Random随机数也可以保证线程的安全,但是Random随机数生成是和种子seed有关,而为了保证线程安全性,Random通过CAS机制来保证线程安全性。
从next()方法中我们可以发现seed是通过自旋锁和CAS来进行修改值的。如果在高并发的场景下,那么可能会导致CAS不断失败,从而导致不断自旋,这样就可能会导致服务器CPU过高。我们可以看一下next的实现:
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));
}
2.为什么要用ThreadLocalRandom
ThreadLocalRandom是ThreadLocal和Random类的组合,它与当前线程隔离。因此,它通过简单地避免对Random对象的任何并发访问,在多线程环境中实现了更好的性能。
一个线程获得的随机数不受另一个线程的影响,而java.util.Random全局提供随机数。
此外,与Random 不同,ThreadLocalRandom不支持显式设置种子。相反,它会覆盖从Random继承的setSeed(long seed)方法,以便在调用时始终抛出UnsupportedOperationException。
现在让我们看一下生成随机int,long和double值的一些方法。
根据Oracle文档,我们只需要调用ThreadLocalRandom.current()方法,它将返回当前线程的ThreadLocalRandom实例。然后,我们可以通过调用类的可用实例方法来生成随机值。
int unboundedRandomValue = ThreadLocalRandom.current().nextInt());
上面的代码可以生成一个没有任何边界的随机int值
int boundedRandomValue = ThreadLocalRandom.current().nextInt(0, 100);
这是一个生成0到100之间的随机int值的示例,值得注意的是:包含下限0,不包含上限100
同样我们也可以与上面示例中所示类似的方式调用nextLong()和nextDouble()方法来生成long和double的随机值。
Java 8还添加了nextGaussian()方法来生成下一个正态分布的值,其值与生成器序列的值相差 0.0和1.0。
与Random类一样,我们也可以使用doubles(),ints()和longs()方法生成随机值流。