ThreadLocalRandom类

Posted wqff-biubiu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadLocalRandom类相关的知识,希望对你有一定的参考价值。

一、Random类

public class RandomTest {

    public static void main(String[] args){
        Random random = new Random();
        for (int i = 0; i < 10; i++){
            System.out.println(random.nextInt());
        }
    }
}
/*
 * nextInt() 源码
 */
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));//获取nextseed采用CAS保证原子性,多线程会使大量线程进行自旋重试,降低了并发性能。
return (int)(nextseed >>> (48 - bits)); }

二、ThreadLocalRandom类

继承了Random重写了nextInt,类似于ThreadLocal的实现,在各自Thread实例中保存自己的seed,具体声明源码如下。

    // The following three initially uninitialized fields are exclusively
    // managed by class java.util.concurrent.ThreadLocalRandom. These
    // fields are used to build the high-performance PRNGs in the
    // concurrent code, and we can not risk accidental false sharing.
    // Hence, the fields are isolated with @Contended.

    /** 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;

ThreadLocalRandom实现

public class ThreadLocalRandomTest {

    public static void main(String[] args){
        ThreadLocalRandom random = ThreadLocalRandom.current();
        for (int i = 0;i < 10; i++){
            System.out.println(random.nextInt(5));
        }
    }
}

/**
 * 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);//Thread.currentThread.threadLocalRandomSeed
        return r;
    }

ThreadLocalRandom主要源码模块

1.unsafe初始化

    // Unsafe mechanics
    private static final sun.misc.Unsafe UNSAFE;
    private static final long SEED;
    private static final long PROBE;
    private static final long SECONDARY;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> tk = Thread.class;
            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);
        }
    }

2.构造方法私有化,提供静态方法current实例化,保证单例

    /** Constructor used only for static singleton */
    private ThreadLocalRandom() {
        initialized = true; // false during super() call
    }

    /**
     * Returns the current thread‘s {@code ThreadLocalRandom}.*/
    public static ThreadLocalRandom current() {
        if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)//当前线程Thread实例中threadLocalRandomProbe为0初始化seed
            localInit();
        return instance;
    }

    /**
     * Initialize Thread fields for the current thread.  Called only
     * when Thread.threadLocalRandomProbe is zero, indicating that a
     * thread local seed value needs to be generated. Note that even
     * though the initialization is purely thread-local, we need to
     * rely on (static) atomic generators to initialize the values.
     */
    static final void localInit() {
        int p = probeGenerator.addAndGet(PROBE_INCREMENT);
        int probe = (p == 0) ? 1 : p; // 不为0,保证单例
        long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
        Thread t = Thread.currentThread();
        UNSAFE.putLong(t, SEED, seed);//存到当前线程的threadLocalRandomSeed中
        UNSAFE.putInt(t, PROBE, probe);//
    }

3.随机数

    /**
     * Returns a pseudorandom {@code int} value between zero (inclusive)
     * and the specified bound (exclusive).
     *
     * @param bound the upper bound (exclusive).  Must be positive.
     * @return a pseudorandom {@code int} value between zero
     *         (inclusive) and the bound (exclusive)
     * @throws IllegalArgumentException if {@code bound} is not positive
     */
    public int nextInt(int bound) {
        if (bound <= 0)
            throw new IllegalArgumentException(BadBound);
        int r = mix32(nextSeed());//重点下一个seed
        int m = bound - 1;
        if ((bound & m) == 0) // power of two
            r &= m;
        else { // reject over-represented candidates
            for (int u = r >>> 1;
                 u + m - (r = u % bound) < 0;
                 u = mix32(nextSeed()) >>> 1)
                ;
        }
        return r;
    }

    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);//取得是当前线程中的threadLocalRandomSeed变量
        return r;
    }

以上是关于ThreadLocalRandom类的主要内容,如果未能解决你的问题,请参考以下文章

ThreadLocalRandom 是线程安全的吗?

ThreadLocalRandom 是线程安全的吗?

还在用 Random?试试 ThreadLocalRandom,好用!

还在用 Random生成随机数了?试试 ThreadLocalRandom,好用!

还在用Random获取随机数?ThreadLocalRandom 性能更佳!

还在用Random获取随机数?ThreadLocalRandom 性能更佳!