掘金 后端 ( ) • 2021-12-02 11:43

一、Random

每个Random实例里面都有一个原子性的种子变量用来记录当前的种子值,当要生成新的随机数时需要根据当前种子计算新的种子并更新回原子变量。

多线程下产生随机数局限性: 在多线程下使用单个Random实例生成随机数时,当多个线程同时计算随机数来计算新的种子时,多个线程会竞争同一个原子变量的更新操作,由于原子变量的更新是CAS操作,同时只有一个线程会成功,所以会造成大量线程进行自旋重试,这会降低并发性能,所以ThreadLocalRandom应运而生。

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

二、ThreadLocalRandom

每个线程都维护一个种子变量,则每个线程生成随机数时都根据自己老的种子计算新的种子,并使用新种子更新老的种子,再根据新种子计算随机数,就不会存在竞争问题了,这会大大提高并发性能

clipboard.png

public class ThreadLocalRandomDemo {
    public static void main(String[] args) {
        // 来获取当前线程随机数生成器
        ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();

        for (int i=0; i<10; i++){
            System.out.println(threadLocalRandom.nextInt(5));
        }
    }
}

总结

首先讲解了Random的实现原理以及Random在多线程下需要竞争种子原子变量更新操作的缺点,从而引出ThreadLocalRandom类。ThreadLocalRandom使用ThreadLocal的原理,让每个线程都持有一个本地的种子变量,该种子变量只有在使用随机数时才会被初始化。在多线程下计算新种子时是根据自己线程内维护的种子变量进行更新,从而避免了竞争。