阿里巴巴JAVA开发手册提到:
. 【推荐】避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一
seed 导致的性能下降。
说明:Random 实例包括 java.util.Random 的实例或者 Math.random()的方式。
正例:在 JDK7 之后,可以直接使用 API ThreadLocalRandom,而在 JDK7 之前,需要编码保
证每个线程持有一个实例。
参考Java中的随机数生成器:Random,ThreadLocalRandom,SecureRandom 和 Java 随机数 Random VS SecureRandom 以及 Java中生成随机数Random、ThreadLocalRandom、SecureRandom、Math.random()的博客。
为什么多线程竞争下,Random实例会因为竞争导致性能下降?
因为Random在生成随机数的时候使用了CAS。
如何使用呢?
Math.random():
它就是一个方法,生成0~1之间的随机数double,也是使用到了Random类。
Random:
Random random = new Random();
Random random = new Random(10);//seed为10
ThreadLocalRandom:
/** The common ThreadLocalRandom */
static final ThreadLocalRandom instance = new ThreadLocalRandom();
//instance是在java.util.concurrent.ThreadLocalRandom类中的属性 ,
//这也就说明了全局只有一个instance实例,而我们的程序调用
//ThreadLocalRandom.current()只是给当前线程初始化了一个种子。
//每个线程都有一个自己的种子,所以就不会发生多线程模式下的竞争。
每一个线程有一个独立的随机数生成器,用于并发产生随机数,能够解决多个线程发生的竞争争夺。效率更高!
ThreadLocalRandom current = ThreadLocalRandom.current();
SecureRandom:
当需要安全性较高的时候用这个类,当然,只需要初始化一次实例就行了。
//使用默认的算法- NativePRNG
SecureRandom secureRandom = new SecureRandom();
//使用SHA1PRNG算法
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
//使用SHA1PRNG算法,指定包名
SecureRandom random1 = SecureRandom.getInstance("SHA1PRNG","SUN");
//使用SHA1PRNG算法,指定provider(构造方法参数是随便写的)
SecureRandom random2 = SecureRandom.getInstance("SHA1PRNG", new Provider("name", 1.1, "inf");
补充:
random.nextInt(10)生成一个0~9之间的数,不会生成10;
可以使用org.apache.commons.lang3包下面的RandomUtils.nextInt(3, 6)方法生成一个3~5之间的数,它使用到的是Random类。