Java中随机数的生成(指定范围)

目录

初级方法(常用)

1. Random类

2. Math.random()

3. 时间戳

高级方法(不常用)

1.ThreadLocalRandom

(1) 基础使用

(2) 优点分析

(3) 缺点分析

2.SecureRandom(真正的随机数)

基础使用

 总结


初级方法(常用)

Java中产生随机数的方法主要有三种:

new Random()
Math.random()
currentTimeMillis()


1. Random类


第一种需要借助java.util.Random类来产生一个随机数发生器,也是最常用的一种,构造函数有两个,Random()和Random(long seed)。
 

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

int randNumber = rand.nextInt(MAX - MIN + 1) + MIN;

2. Math.random()


而第二种方法返回的数值是[0.0, 1.0)的double型数值,由于double类数的精度很高,可以在一定程度下看做随机数,借助(int)来进行类型转换就可以得到整数随机数了

num = (int)(Math.random()*100) + 1;

3. 时间戳


这种方法在循环中连续产生随机数,由于是同一时间,产生的结果可能相同

至于第三种方法虽然不常用,但是也是一种思路。方法返回从1970年1月1日0时0分0秒(这与UNIX系统有关)到现在的一个long型的毫秒数,取模之后即可得到所需范围内的随机数。

public void test3() {
    int max = 100, min = 1;
    long randomNum = System.currentTimeMillis();
    int ran = (int) (randomNum % (max - min) + min);
    //循环同一时间会产生相同的数
    System.out.print(ran);
}

高级方法(不常用)

1.ThreadLocalRandom

ThreadLocalRandom 是 JDK 1.7 新提供的类,它属于 JUC(java.util.concurrent)下的一员,为什么有了 Random 之后还会再创建一个 ThreadLocalRandom? ​

在多线程竞争比较激烈的场景可以使用 ThreadLocalRandom 来解决 Random 执行效率比较低的问题。 ​当我们第一眼看到 ThreadLocalRandom 的时候,一定会联想到一次类 ThreadLocal,确实如此。ThreadLocalRandom 的实现原理与 ThreadLocal 类似,它相当于给每个线程一个自己的本地种子,从而就可以避免因多个线程竞争一个种子,而带来的额外性能开销了

(1) 基础使用

接下来我们使用 ThreadLocalRandom 来生成一个 0 到 10 的随机数(不包含 10),实现代码如下:

// 得到 ThreadLocalRandom 对象
ThreadLocalRandom random = ThreadLocalRandom.current();
for (int i = 0; i < 10; i++) {
    // 生成 0-9 随机整数
    int number = random.nextInt(10);
    // 打印结果
    System.out.println("生成随机数:" + number);
}

(2) 优点分析

ThreadLocalRandom 结合了 Random 和 ThreadLocal 类,并被隔离在当前线程中。因此它通过避免竞争操作种子数,从而在多线程运行的环境中实现了更好的性能,而且也保证了它的线程安全

另外,不同于 Random, ThreadLocalRandom 明确不支持设置随机种子。它重写了 Random 的 setSeed(long seed) 方法并直接抛出了 UnsupportedOperationException 异常,因此降低了多个线程出现随机数重复的可能性

(3) 缺点分析

虽然 ThreadLocalRandom 不支持手动设置随机种子的方法,但并不代表 ThreadLocalRandom 就是完美的,当我们查看 ThreadLocalRandom 初始化随机种子的方法 initialSeed() 源码时发现,默认情况下它的随机种子也是以当前时间有关

当我们设置了启动参数“-Djava.util.secureRandomSeed=true”时,ThreadLocalRandom 会产生一个随机种子,一定程度上能缓解随机种子相同所带来随机数可预测的问题,然而默认情况下如果不设置此参数,那么在多线程中就可以因为启动时间相同,而导致多个线程在每一步操作中都会生成相同的随机数

2.SecureRandom(真正的随机数)

SecureRandom 继承自 Random,该类提供加密强随机数生成器。SecureRandom 不同于 Random,它收集了一些随机事件,比如鼠标点击,键盘点击等,SecureRandom 使用这些随机事件作为种子。这意味着,种子是不可预测的,而不像 Random 默认使用系统当前时间的毫秒数作为种子,从而避免了生成相同随机数的可能性。 ​

基础使用

// 创建 SecureRandom 对象,并设置加密算法
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
for (int i = 0; i < 10; i++) {
    // 生成 0-9 随机整数
    int number = random.nextInt(10);
    // 打印结果
    System.out.println("生成随机数:" + number);
}

 总结

对于绝大数应用场景来说,使用 Random 已经足够了。当在竞争比较激烈的场景下可以使用 ThreadLocalRandom 来替代 Random,但如果对安全性要求比较高的情况下,可以使用 SecureRandom 来生成随机数,因为 SecureRandom 会收集一些随机事件来作为随机种子,所以 SecureRandom 可以看作是生成真正随机数的一个工具类。

鸣谢

Java中生成随机数的4种方式! - 腾讯云开发者社区-腾讯云 (tencent.com)

你可能感兴趣的:(java,笔记,java,开发语言)