Random在日常開發過程中還是挺常用的,用於生成隨機值;
Random random = new Random();
random.nextInt(100);
/**
*nextInt(100)實際調用的方法是next(int bits)
*
*/
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生成隨機數是線程安全的,但是在多線程併發的情況下,自旋操作會增加CPU的負擔,而ThreadlocalRandom能夠有效的降低這種壓力;從名稱上大致能夠看出ThreadlocalRandom的實現原理與Threadlocal相似,多個線程相互隔離的。下面是ThreadlocalRandom的next()的實現。
public int nextInt(int bound) {
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
int r = mix32(nextSeed());
int m = bound - 1;
if ((bound & m) == 0) //bound是2次冪
r &= m;
else { // 不是2次冪
for (int u = r >>> 1;
u + m - (r = u % bound) < 0;
u = mix32(nextSeed()) >>> 1) ;
}
return r;
}
在ThreadlocalRandom裏面重寫了next方法,並未沿用Random中的cas原子性操作,隨機數生成的種子seed並未放在當前類中,而是通過nextSeed()獲取seed的。
final long nextSeed() {
Thread t; long r; // read and update per-thread seed
UNSAFE.putLong(t = Thread.currentThread(), SEED,
r = UNSAFE.getLong(t, SEED) + GAMMA);
return r;
}
而SEED常量初始化在創建實例的時候;ThreadlocalRandom的實例獲取方式
ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
通過靜態代碼塊進行一些變量的初始化。
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
//獲取線程Thread中的threadLocalRandomSeed常量,作爲seed
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);
}
}
在ThreadLocalRandom實例化的時候將靜態代碼塊中初始化的參數寫進ThreadLocalRandom 類中;
public static ThreadLocalRandom current() {
if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
localInit();
return instance;
}
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);
}
在Thread中
/** The current seed for a ThreadLocalRandom */
@sun.misc.Contended("tlr")
long threadLocalRandomSeed;
/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
@sun.misc.Contended("tlr")
int threadLocalRandomProbe;
/** Secondary seed isolated from public ThreadLocalRandom sequence */
@sun.misc.Contended("tlr")
int threadLocalRandomSecondarySeed;
其中加這個註解的原因@sun.misc.Contended,就是避免僞共享。