2. Java走过的坑-不随便设置随机种子

简介:

下面来看一段代码

public class RandomSeed {

    public static void main(String[] args) {
        Random random = new Random();
        for(int i=1; i<4; i++){
            System.out.println("第"+ i +"次" + random.nextInt());
        }
    }
}

控制台输出
第1次-19943036062次-1871578223次-1572664715

代码很简单,我们一般也都是这么获取随机数的,我们看到除数的三次结果都是不同的,也都是随机数,下面再看看一组程序

public static void main(String[] args) {
    // 多运行几次
    Random random = new Random(1000);
    for(int i=1; i<4; i++){
        System.out.println("第"+ i +"次" + random.nextInt());
    }
}

控制台输出
第1次-1244746321210604938713次-1826063944

计算机不同输出的随机数也不同,但有一点是相同的:在同一台机器上不管允许多少次,打印出的随机数都是相同的,也就是说第一次运行会打印出这三个随机数,第二次打印还是这三个随机数,出现问题了,现在不是随机数不随机了吗?

我们找找问题何在,那是因为产生随机数的"种子"被固定了,在Java中随机数的产生取决于种子,随机数和种子之间应该遵守以下规则:

  • 种子不同,产生不同的随机数

  • 种子相同,实例不同产生不同的随机数

看完上面2个规则,用代码来解释

// 这是JDK中random类的无参构造函数
public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}
private static long seedUniquifier() {
        // L'Ecuyer, "Tables of Linear Congruential Generators of
        // Different Sizes and Good Lattice Structure", 1999
        for (;;) {
            long current = seedUniquifier.get();
            long next = current * 181783497276652981L;
            if (seedUniquifier.compareAndSet(current, next))
                return next;
    }
}
private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);

取了seedUniquifier ^ System.nanoTime()的返回值,seedUniquifier的代码我没细看,总之就是设置当前种子的算法,看来这样的不会重复的随机数了。

public Random(long seed) {
        if (getClass() == Random.class)
            this.seed = new AtomicLong(initialScramble(seed));
        else {
            // subclass might have overriden setSeed
            this.seed = new AtomicLong();
            setSeed(seed);
        }
    }

这段代码是传入了一个参数的随机,实际上我们设定了随机种子是1000,运行多次的随机数是一样的因为永远都走

this.seed = new AtomicLong(initialScramble(seed));

这一步,虽然返回的是不同的实例,但是固定的种子还是会导致多次运行出现相同的随机数。


总结:

在java中有2种方法可以获取随机数:

java.util.Random和Math.random() 获取随机数,两者功能相同,一般非必须情况不要设置随机种子。

目录
相关文章
|
1月前
|
Java
【Java】— —实现人物对象的增、删、改、查(注:对象的删除以逻辑删除为主,在person类中设置“删除状态字段”,字删除该字段时,将状态改为有效。)
【Java】— —实现人物对象的增、删、改、查(注:对象的删除以逻辑删除为主,在person类中设置“删除状态字段”,字删除该字段时,将状态改为有效。)
33 0
|
17天前
|
Java
java中jar启动设置内存大小java -jar 设置堆栈内存大小
java中jar启动设置内存大小java -jar 设置堆栈内存大小
11 1
|
1月前
|
XML Java 数据库
java如何设置事务超时时间
【2月更文挑战第16天】
|
2月前
|
NoSQL Java Redis
【Java专题_09】生产环境Jvm参数设置
【Java专题_09】生产环境Jvm参数设置
|
3月前
|
XML Java Android开发
Java学习—Eclipse/Idea如何设置自动提示
Java学习—Eclipse/Idea如何设置自动提示
|
3月前
|
小程序 JavaScript Java
基于Java的大学生心理健康答题小程序设计与实现(亮点:选题新颖、可以发布试卷设置题目、自动判卷、上传答案、答案解析)
基于Java的大学生心理健康答题小程序设计与实现(亮点:选题新颖、可以发布试卷设置题目、自动判卷、上传答案、答案解析)
49 0
|
4月前
|
Java
【Java代码】反射机制处理传递给mapper文件的非Map类型参数对象(指定属性为空则设置默认值)
【Java代码】反射机制处理传递给mapper文件的非Map类型参数对象(指定属性为空则设置默认值)
28 0
|
4月前
|
Java
java环境变量设置
在 "系统变量" 中设置 3 项属性,JAVA_HOME、PATH、CLASSPATH(大小写无所谓),若已存在则点击"编辑",不存在则点击"新建"。 变量设置参数如下: 变量名:JAVA_HOME 变量值:C:\Program Files (x86)\Java\jdk1.8.0_91 // 要根据自己的实际路径配置 变量名:CLASSPATH 变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; //记得前面有个"." 变量名:Path 变量值:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
29 0
|
4月前
|
JSON 前端开发 Java
12:CORS跨域设置-Java Spring
12:CORS跨域设置-Java Spring
50 0
|
4月前
|
Java
java环境变量设置
磁盘管理 查看挂载情况 lsblk -f 挂载步骤 1.虚拟机增加硬盘 2.分区命令 fdisk /dev(设备文件)/sdb m 显示命令列表 p 显示磁盘分区 n 新增分区 d 删除分区 w 写入并退出 3.格式化磁盘,并挂载 mkfs -t ext4 /dev/sdb1 mount /dev/sdb1 文件路径 4.卸载 umount /dev/sdb1 或者 umount /文件
18 0