Random使用最广泛的随机数生成工具,即使Math.random()的底层也是使用Random实现
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
接下来看看Random的源码解析
/**
*源码版本:JDK 11
*/
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));
}
根据以上源码可以看出,在使用oldseed获取nextseed的时候,如果是多线程操作,则同一时刻只会有一个线程CAS成功,其他失败的线程会通过自旋等待获取nextseed,因此会有一定的性能消耗.
这也就是为什么JDK1.7会引入ThreadLocalRandom的原因了,主要解决多线程情况下Random的执行效率问题.
ThreadLocalRandom:
ThreadLocalRandom继承于Random类
ThreadLocalRandom的源码解析:
/**
* 源码版本:JDK 11
*/
final long nextSeed() {
Thread t; long r; // read and update per-thread seed
//把当前线程作为参数生成nextseed
UNSAFE.putLong(t = Thread.currentThread(), SEED,
r = UNSAFE.getLong(t, SEED) + GAMMA);
return r;
}
从上述源码看出,ThreadLocalRandom并不是像Thread那样使用CAS喝自旋来获取nextseed,而是在每个线程使用线程变量存储自己的oldseed和生成nextseed,因此可以避免多线程竞争和自旋等待的时间,所以在多线程环境下性能更高.
ThreadLocalRandom注意事项
多线程不能共享一个ThreadLocalRandom对象,否则会造成生成的随机数都相同