随机数 ThreadLocalRandom
public static void main(String[] args) {
ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
for (int i = 0; i < 10; i++) {
//(1)获取5以内的随机数
System.out.println(threadLocalRandom.nextInt(5));
}
}
- 1、int nextInt(int bound)
public int nextInt(int bound) {
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
//(1.1)使用当前种子值获取新种子值
int r = mix32(nextSeed());
int m = bound - 1;
//(1.2)使用新种子值获取随机数
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;
}
- 1.1、long nextSeed()
final long nextSeed() {
Thread t; long r; // read and update per-thread seed
//(1.1.1)
//r = UNSAFE.getLong(t, SEED)获取当前线程中对应的SEED值
//UNSAFE.putLong(Thread.currentThread(), SEED, SEED+GAMMA)
UNSAFE.putLong(t = Thread.currentThread(), SEED,
r = UNSAFE.getLong(t, SEED) + GAMMA);
return r;
}
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
//获取到对应线程中threadLocalRandomSeed为当前种子值
SEED = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSeed"));
PROBE = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomProbe"));
SECONDARY = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSecondarySeed"));
} catch (Exception e) {
throw new Error(e);
}
}
在Random中实现将老种子值替换为新的种子值的时候,采用的是CAS算法,所以在多线程高并发的情况下,会出现多个线程竞争更新原子变量种子值,所以性能会受影响,但是使用ThreadLocalRandom就不会出现此情况。</br> ThreadLocalRandom继承了Random类,并且重写了nextInt()方法。在1.1中,先是通过UNSAFE.getLong()方法(入参是Thread.currentThread()和SEED,其中SEED = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomSeed"));即当前线程中的threadLocalRandomSeed值)获取当前线程中当前的种子值,然后通过UNSAFE.putLong()方法(入参是Thread.currentThread():当前线程, SEED:当前种子值, SEED+GAMMA:新的种子值),设置threadLocalRandomSeed为SEED+GAMMA。因为这里的种子值都是线程级别的,所以不需要原子级别的变量,从而就不会出现竞争种子值变更情况。