本文转载自微信公众号「一个程序员的原理成长」,作者一个程序员的分析成长。转载本文请联系一个程序员的原理成长公众号。 Random小结: 每个Random实例里面都有一个原子性的种子变量用来记录当前的种子值,当要生成新的原理随机数时需要根据当前的种子计算新的云南idc服务商种子并更新种子变量。当在多线程环境下,分析多个线程会竞争同一个原子变量的原理更新操作,由于原子变量的分析更新时CAS操作,同时只有一个线程会成功,原理所以会造成大量线程进行自旋重试,分析从而降低并发性能。原理 可能出现的症状:如果并发请求非常多,自旋锁一直重试,那么CPU会一直飙升。 这个方法用来创建ThreadLocalRandom随机数生成器,如果当前线程中threadLocalRandomProbe的变量值为0,则说明是第一次调用current方法,那么就调用localInit方法初始化种子变量。 这里使用了延迟初始化,在localInit方法中,并没有初始化种子变量,服务器租用而是在需要生成随机数的时候再生成种子变量,这是一种优化。 mix32是一个固定的算法,这里重点看下nextSeed方法,当第一次调用的时候进行初始化,获取当前线程threadLocalRandomSeed的值(第一次默认值为0) + 种子增量,如果不是第一次那么获取旧种子的值 + 种子增量生成新的种子变量并设置回去。这样的话多线程环境下就避免了竞争,因为threadLocalRandomSeed是Thread的一个变量,属于线程级别。站群服务器1、分析Random类及其局限性
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; } protected int next(int bits) { long oldseed, nextseed; // 这是一个原子性的变量 AtomicLong seed = this.seed; do { // (1)、获取老的分析种子 oldseed = seed.get(); // (2)、计算出新的原理种子 nextseed = (oldseed * multiplier + addend) & mask; // (3)、CAS操作更新老的分析种子 } while (!seed.compareAndSet(oldseed, nextseed)); return (int)(nextseed >>> (48 - bits)); } 2、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); }