记一次代码重构时发现的问题

668 阅读1分钟

今天重构一段前人写的老代码的时候,看到for循环中本应完全随机的数值出现较高频率的相同,发现是new Random(System.currentTimeMillis())出现的问题

只需将

Random random =new Random(System.currentTimeMillis());

替换为更为简便的

Random random =new Random();

这样,问题就解决啦!

为什么会这样呢?

我们只需查看JDk的源码,就会发现原因其实很简单。

在使用new Random(System.currentTimeMillis())的时候,Random调用的是

    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);
        }
    }

而使用new Random(),则是调用的

    public Random() {
        this(seedUniquifier() ^ System.nanoTime());
    }

我们在使用new Random(System.currentTimeMillis())的时候,会获取到当前系统毫秒级别的时间作为种子,那么在一些简单的循环中,就有可能得到相同的时间,这样就完全失去了随机性。

System.nanoTime()则是精确到微毫秒的系统计时器的当前值,值得注意的是,这个方法不可以用来获取系统当前时间,只能用作计时器,比如计算一段代码的运行耗时。

所以,想要使用完全随机数时,直接new Random()就好,就不要在传入其他东西啦