Random伪随机

Random生成的随机数都是伪随机数,有一定的规律。

 

1. 不带种子参数

系统默认指定参数(成员变量为static类型,通过compareAndSet, 实现不同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);

 其中System.nanoTime() 是与系统时间无关的纳米维度时间,和CPU和线程有关

2. 带种子参数

new Random(seed).nextInt(N), 值为[0,N)

针对带种子参数情况

for (int i = 0; i < 100; i++) {

      int rd = new Random(seed).nextInt(N); // 每次rd 值都一样, 规律为同一个seed, 创建一个Random对象,产生的随机数列表是固定的

}

 

System.nanoTime()

返回当前JVM的高精度时间。该方法只能用来测量时段而和系统时间无关。它的返回值是从某个固定但随意的时间点开始的(可能是未来的某个时间)。不同的JVM使用的起点可能不同

 

System.nanoTime()的返回值要用相减是否大于0来判断调用的先后顺序, 但不能用>或<来判断.

System.nanoTime()返回的数值实际是64位无符号数, 随着进程运行时间增长, 溢出后再从0开始, 赋值给long类型相当于当做补码数(有符号数)使用, 其值循环规律如下:

最小负数 -> 0 -> 最大正数 -> 最小负数 -> ...

为防止溢出,时间比较只能使用 相减,而不能使用大于小于号, 主要由4种情况:

正正: t1 -  t2 > 0;

负负: t1 - t2 > 0;

正负: t1 - t2 > 0;  // 大负数减去大正数, 溢出 答出正数

负正: t1 -  t2 > 0; //小正数减去小负数, 不溢出,答出正数

 

System.naoTime() 和System.currentTimeMillis()存在并发性能问题

​其实在串行情况下这两个api其实性能很好,但是在并发情况下回急剧下降,原因在于计时器在所有进程之间共享,并且其还一直在发生变化,当大量线程尝试同时去访问计时器的时候,就涉及到资源的竞争,于是也就出现并行效率远低于串行效率的现象了。所以在高并发场景下要慎重使用System.nanoTime()和System.currentTimeMillis()这两个API。 可以使用 CountDownLatch测试相关性能

 

参考:

Random函数及其种子的作用: https://www.cnblogs.com/huiAlex/p/8057737.html

关于System.nanoTime():  https://www.cnblogs.com/jice/p/10521948.html

System.nanoTime()和System.currentTimeMillis()性能问题: https://www.cnblogs.com/cord/p/9343090.html

 

posted on 2019-11-25 11:06  wangsong412  阅读(1523)  评论(0编辑  收藏  举报