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 -> 最大正数 -> 最小负数 -> ...
为防止溢出,时间比较只能使用 相减,而不能使用大于小于号
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