前言
java.util.Random的源码阅读
介绍
java.util.Random是Java的一个实用工具类库中的一个类,提供了产生各种类型随机数的方法
// 无参构造方法
public Random() {
// 生成种子 seedUniquifier方法和System.nanoTime()时间进行 异或运算
this(seedUniquifier() ^ System.nanoTime());
}
// 初始的种子
private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);
private static long seedUniquifier() {
// 多线程可以会赋值失败,所以使用for循环
for (;;) {
// 当前预期值
long current = seedUniquifier.get();
// 要更新的值
long next = current * 181783497276652981L;
// 使用CAS操作更新seedUniquifier
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
private final AtomicLong seed;
// 有参构造方法
public Random(long seed) {
if (getClass() == Random.class)
this.seed = new AtomicLong(initialScramble(seed));
else {
// 子类可以重写setSeed()方法
this.seed = new AtomicLong();
setSeed(seed);
}
}
private static final long multiplier = 0x5DEECE66DL;
private static final long mask = (1L << 48) - 1;
// 把用户设置的种子进行运算 返回long
private static long initialScramble(long seed) {
return (seed ^ multiplier) & mask;
}
synchronized public void setSeed(long seed) {
this.seed.set(initialScramble(seed));
haveNextNextGaussian = false;
}
public int nextInt(int bound) {
// 判断 bound
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
// 根据旧种子生成新种子
int r = next(31);
// 下面这些代码都是根据新种子计算随机数
int m = bound - 1;
if ((bound & m) == 0)
r = (int)((bound * (long)r) >> 31);
else {
for (int u = r;
u - (r = u % bound) + m < 0;
u = next(31))
;
}
return r;
}
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
// 获取旧种子
oldseed = seed.get();
// 用旧种子去生成新种子
nextseed = (oldseed * multiplier + addend) & mask;
// 使用CAS,多线程下只能有一个线程更新为新种子,
// 其他线程只能通过循环重新获取更新后的种子作为当前种子去计算新的种子
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
结论:Random的实例是线程安全的,内部使用了原子类和CAS确保多线程下安全,但由于原子变量的更新是CAS操作,同时只有一个线程成功,造成了大量线程进行自旋重试操作,从而降低了并发性能