先查看random 源码
1.有一个成员变量seed,类型为AtomicLong,无参构造方法,会通过特定的算法得到一个值 * 当前纳秒数得到一个seed。随机性就体现再这个当前纳秒数。算法计算的值是固定的。所以,如果指定seed值,那么产生的随机数就是一样的。
2.next每次生成随机数的算法都是固定的,没有掺杂随机因素。所以只要seed固定。每次调用next方法产生的随机数也是固定的。
3.random多线程并发下,使用的就是atomicLong 的的cas变化seed。所以,这里就有个缺点,多线程下,cas自旋消耗比较严重。
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
public Random(long seed) {
if (getClass() == Random.class)
this.seed = new AtomicLong(initialScramble(seed));
else {
// subclass might have overriden setSeed
this.seed = new AtomicLong();
setSeed(seed);
}
}
private static final AtomicLong seedUniquifier
= new AtomicLong(8682522807148012L);
private static long seedUniquifier() {
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
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));
}
因为多线程下random自旋消耗比较大。所以有一个ThreadLocalRandom,顾名思义,和ThreadLocal原理差不多,线程本身维护自己的random(其实是random的seed),之后线程根据自己的seed产生随机数。自然就没有了多个线程自旋争夺同一个seed的并发消耗。
可以看到都是通过unsafe获取当前线程的当前变量值。
public static ThreadLocalRandom current() {
if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
localInit();
return instance;
}
1.ThreadLocalRandom的随机性就体现在seeder这个atomicLong。第一次初始化的时候(也就是第一个调用current方法的线程),会通过当前毫秒数和当前纳秒数,获取到seed,之后每个线程调用一次current方法,都会通过old seed,通过特定的算法,获取到新seed,然后每个线程自己维护起来。
2.除了通过时间来达到随机效果之后。具体的算法和random也不一样,算法不研究。
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);
}
private static final AtomicLong seeder = new AtomicLong(initialSeed());
private static long initialSeed() {
String pp = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
"java.util.secureRandomSeed"));
if (pp != null && pp.equalsIgnoreCase("true")) {
byte[] seedBytes = java.security.SecureRandom.getSeed(8);
long s = (long)(seedBytes[0]) & 0xffL;
for (int i = 1; i < 8; ++i)
s = (s << 8) | ((long)(seedBytes[i]) & 0xffL);
return s;
}
return (mix64(System.currentTimeMillis()) ^
mix64(System.nanoTime()));
}