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,就是避免伪共享。