ThreadLocalRandom

混江龙づ霸主 提交于 2020-03-20 13:20:58

3 月,跳不动了?>>>

一、Random

在创建Random类时会生成seed,seed用于生成随机数。在每次生成随机数后,都会使用CAS的方式更新seed,所以Random是线程安全的。但是在并发度较高的情况下,CAS的效率会变得很低。

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));
}

二、ThreadLocalRandom

  1. current()
static final ThreadLocalRandom instance = new ThreadLocalRandom();

public static ThreadLocalRandom current() {
    if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
        localInit();
    return instance;
}

current()首先查看当前线程中的PROBE(探针)是否初始化,如果是,则返回一个ThreadLocalRandom的单例;如果否,则调用localInit()进行初始化。

  1. localInit()
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);
}

localInit()生成probe和seed,并存入当前线程。probe和seed在Thread中的定义如下:

@sun.misc.Contended("tlr")
int threadLocalRandomProbe;

@sun.misc.Contended("tlr")
long threadLocalRandomSeed;
  1. nextInt()
public int nextInt() {
    return mix32(nextSeed());
}

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;
}

由此可见,虽然ThreadLocalRandom是单例,所有线程共用一个,但是生成随机数的nextInt()却是使用各自线程中的seed,线程之间是相互隔离的。所以ThreadLocalRandom在高并发场景下的性能要优于Random。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!