🟨 ThreadLocalRandom
2022年10月10日
- Java
🟨 ThreadLocalRandom
1. 类注释
Random
类每次获取随机数时,通过CAS
修改 seed 值,多线程并发下,只能有一个线程成功修改 seed 值,其余线程无限重试- 冲突高时,影响并发效率
ThreadLocalRandom
类每次获取随机数时,通过 Unsafe 类直接修改seed
值,各线程下 seed 互不影响,只与 当前线程 有关,因此也无需通过 CAS 设置- 高并发下,不影响并发效率
使用
ThreadLocalRandom rand = ThreadLocalRandom.current(); // 获取当前线程对应的 ThreadLocalRandom 单例
int rint = rand.nextInt(10); // 生成 [0, 10) 的随机数
double rdou = rand.nextDouble(3.0, 29); // 生成 [3.0, 29) 的随机数
2. 源码
public class ThreadLocalRandom extends Random {
// 原子类 -- 初始化用
private static final AtomicInteger probeGenerator = new AtomicInteger();
private static final int PROBE_INCREMENT = 0x9e3779b9; // 初始化时,原子类的每次增长值
private static final AtomicLong seeder = new AtomicLong(initialSeed()); // 原子类 -- 种子值
private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL; // 种子的增长值
boolean initialized; // 仅在单例初始化期间使用的字段。构造函数完成时为真。
// 私有构造方法,只能通过 ThreadLocalRandom.current() 得到 -- 单例模式
private ThreadLocalRandom() {
initialized = true; // false during super() call
}
static final ThreadLocalRandom instance = new ThreadLocalRandom();
// 提供的外部访问单例
public static ThreadLocalRandom current() {
if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
localInit();
return instance;
}
// 为当前线程初始化线程字段
// 仅在 Thread.threadLocalRandomProbe 为零时调用,表示需要生成线程本地种子值。
// 即使初始化是纯线程本地的,我们也需要依赖(静态)原子生成器来初始化值。
static final void localInit() {
int p = probeGenerator.addAndGet(PROBE_INCREMENT);
int probe = (p == 0) ? 1 : p; // skip 0
long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT)); // 初始化种子值
Thread t = Thread.currentThread();
UNSAFE.putLong(t, SEED, seed);
UNSAFE.putInt(t, PROBE, probe);
}
// public 方法中获取随机数时,用到
// seed 的生成只与 当前线程有关,因此 多线程下无冲突
final long nextSeed() {
Thread t = Thread.currentThread();
long r = UNSAFE.getLong(t, SEED) + GAMMA;
UNSAFE.putLong(t, SEED, r);
return r;
}
// ---------- 提供的 外部方法 ---------------
// 返回 [origin, bound) 随机 int 值 --> ThreadLocalRandom 独有
public int nextInt(int origin, int bound) {
if (origin >= bound)
throw new IllegalArgumentException(BadRange);
return internalNextInt(origin, bound);
}
// 返回 [0, bound) 随机 int 值 --> 重写 Random 方法
public int nextInt(int bound) {
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
int r = mix32(nextSeed());
int m = bound - 1;
if ((bound & m) == 0) // power of two
r &= m;
else { // reject over-represented candidates
for (int u = r >>> 1;
u + m - (r = u % bound) < 0;
u = mix32(nextSeed()) >>> 1)
;
}
return r;
}
// 返回 [0, 1) 随机 int 值 --> 重写 Random 方法
public int nextInt() {
return mix32(nextSeed());
}
public long nextLong() {
return mix64(nextSeed());
}
// ThreadLocalRandom 独有
public double nextDouble(double bound) {
if (!(bound > 0.0))
throw new IllegalArgumentException(BadBound);
double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
return (result < bound) ? result : // correct for rounding
Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
}
public float nextFloat() {
return (mix32(nextSeed()) >>> 8) * FLOAT_UNIT;
}
public boolean nextBoolean() {
return mix32(nextSeed()) < 0;
}
}
3. Random
public class Random implements java.io.Serializable {
// 种子值
private final AtomicLong seed;
private static final long multiplier = 0x5DEECE66DL;
private static final long mask = (1L << 48) - 1;
// 构造函数 - 种子初始值与 某个固定值 & 当前时间 有关
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
// 构造函数 - 指定 seed 初始值
public Random(long seed) {
if (getClass() == Random.class)
this.seed = new AtomicLong(initialScramble(seed));
else {
this.seed = new AtomicLong();
setSeed(seed);
}
}
// 生成 seed -- 固定值
private static long seedUniquifier() {
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
// 用于 初始化 时,生成 seed 的一部分 --> 固定值
private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);
// 根据指定 seed 初始值生成 满足条件的 seed
private static long initialScramble(long seed) {
return (seed ^ multiplier) & mask;
}
// 根据指定 seed 生成 随机生成器的 seed
synchronized public void setSeed(long seed) {
this.seed.set(initialScramble(seed));
haveNextNextGaussian = false;
}
// -------------- 公开方法 -----------------------
//
public int nextInt() {
return next(32);
}
//
public int nextInt(int bound) {
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
int r = next(31);
int m = bound - 1;
if ((bound & m) == 0) // i.e., bound is a power of 2
r = (int)((bound * (long)r) >> 31);
else {
for (int u = r;
u - (r = u % bound) + m < 0;
u = next(31));
}
return r;
}
//
public double nextDouble() {
return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
}
// 生产下一个随机数 -- 可以看到使用 CAS 保证每次只有一个线程能够成功进入,其他线程只能无限失败重试
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));
}
}