javaSE 并发包 ThreadLocalRandom类原理剖析

ThreadLocalRandom类原理剖析

Random的缺陷

原来的Random类的产生一个新随机数的树的步骤为:

  1. 首先根据老的种子生成新的种子。
  2. 然后根据新的种子来计算新的随机数。

代码:

 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;

    }

但是在多线程的情况下,多个线程可能都是拿到的同一个老的种子以计算出新的种子,产生的新的种子是一样的,显然就是不是我们所预期的。因此random函数使用一个原子变量达到了第一个线程拿到老的种子计算出新的种子后,第二个线程就要丢弃自己拿到的老的种子而使用第一个线程产生的新的种子作为老种子来计算出自己新的种子。保证在多个线程中产生的随机数值是随机的。

代码: 

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));//使用CAS操作用新的种子更新老的种子,失败的线程会通过线程循环获取更新后的新种子当做当前种子去计算

        return (int)(nextseed >>> (48 - bits));//使用固定算法根据新的种子计算随机数

}

多个线程竞争同一个原子变量的更新操作,由于是CAS操作,只会有一个成功,大部分失败的线程会进行自旋重试,降低并发性能,因此ThreadLocalRandom应运而生。

ThreadLocalRandom的原理

因为Random类的缺点是多个线程会使用同一个原子性种子变量,而ThreadLocalRandom使用ThreadLocalRandom.current()来获取当前线程的随机数生产器。原理是将之前的多个线程竞争同一个原子变量让每个线程都复制一份,每个线程生成随机数都是根据自己老的种子生成新的种子来计算出随机数。同ThreadLocal的原理相同。

 

ThreadLocalRandom使用

 ThreadLocalRandom tlr = ThreadLocalRandom.current();

  System.out.println(tlr.nextInt(10,50));//生成一个10~50之间的随机数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值