随机数 ThreadLocalRandom简单介绍

随机数 ThreadLocalRandom

    public static void main(String[] args) {
        ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
        for (int i = 0; i < 10; i++) {
            //(1)获取5以内的随机数
            System.out.println(threadLocalRandom.nextInt(5));
        }
    }
  • 1、int nextInt(int bound)
    public int nextInt(int bound) {
        if (bound <= 0)
            throw new IllegalArgumentException(BadBound);
        //(1.1)使用当前种子值获取新种子值
        int r = mix32(nextSeed());
        int m = bound - 1;
        //(1.2)使用新种子值获取随机数
        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;
    }
  • 1.1、long nextSeed()
    final long nextSeed() {
        Thread t; long r; // read and update per-thread seed
        //(1.1.1) 
        //r = UNSAFE.getLong(t, SEED)获取当前线程中对应的SEED值
        //UNSAFE.putLong(Thread.currentThread(), SEED, SEED+GAMMA)
        UNSAFE.putLong(t = Thread.currentThread(), SEED,
                       r = UNSAFE.getLong(t, SEED) + GAMMA);
        return r;
    }
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> tk = Thread.class;
            //获取到对应线程中threadLocalRandomSeed为当前种子值
            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);
        }
    }

在Random中实现将老种子值替换为新的种子值的时候,采用的是CAS算法,所以在多线程高并发的情况下,会出现多个线程竞争更新原子变量种子值,所以性能会受影响,但是使用ThreadLocalRandom就不会出现此情况。</br> ThreadLocalRandom继承了Random类,并且重写了nextInt()方法。在1.1中,先是通过UNSAFE.getLong()方法(入参是Thread.currentThread()和SEED,其中SEED = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomSeed"));即当前线程中的threadLocalRandomSeed值)获取当前线程中当前的种子值,然后通过UNSAFE.putLong()方法(入参是Thread.currentThread():当前线程, SEED:当前种子值, SEED+GAMMA:新的种子值),设置threadLocalRandomSeed为SEED+GAMMA。因为这里的种子值都是线程级别的,所以不需要原子级别的变量,从而就不会出现竞争种子值变更情况。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容