【发布时间】:2014-04-07 17:49:36
【问题描述】:
我通过点击按钮多次执行了以下代码:
int UP = 4;
Log.println(Log.DEBUG, "random", new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
);
我很惊讶在日志中得到了这个:
04-07 21:26:36.659: D/random(15640): 1 1 1 1 1 1 1 1
04-07 21:26:37.059: D/random(15640): 2 2 2 2 2 2 2 2
04-07 21:26:37.429: D/random(15640): 2 2 2 2 2 2 2 2
04-07 21:26:37.789: D/random(15640): 2 2 2 2 2 2 2 2
04-07 21:26:38.119: D/random(15640): 1 1 1 1 1 1 1 1
04-07 21:26:38.429: D/random(15640): 1 1 1 1 1 1 1 1
04-07 21:26:38.739: D/random(15640): 1 1 1 1 1 1 1 1
04-07 21:26:39.019: D/random(15640): 2 2 2 2 2 2 2 2
04-07 21:26:39.319: D/random(15640): 2 2 2 2 2 2 2 1
04-07 21:26:39.599: D/random(15640): 2 1 1 1 1 1 1 1
——当然,这些序列绝对是非随机的。
我知道,我应该创建 Random 对象的一个实例,并根据需要多次调用它的 nexInt()。 但是每次创建新的 Random 实例时,Java 都会更改静态种子数by Random() 构造函数:
public Random() {
this(++seedUniquifier + System.nanoTime());
}
private static volatile long seedUniquifier = 8682522807148012L;
因此产生的序列应该是随机的,无论我们使用一个对象还是每次都使用新对象。但由于某种原因,它们不是。
我决定继续我的研究,用不同的论点致电nextInt()。而我接下来看到的,更让我吃惊。我注意到每次我选择UP 常数作为2 的幂,new Random().nextInt(UP) 的结果绝对是非随机的,但是当我选择不同的数字 时,一切还可以。
向上 = 8:
04-07 21:43:47.169: D/random(15789): 5 4 4 4 4 5 5 5
04-07 21:43:47.809: D/random(15789): 7 7 7 7 7 7 7 7
04-07 21:43:48.249: D/random(15789): 6 7 7 7 7 6 6 6
04-07 21:43:48.619: D/random(15789): 6 6 6 6 6 6 6 6
04-07 21:43:48.999: D/random(15789): 5 5 5 5 5 5 4 4
04-07 21:43:49.399: D/random(15789): 4 4 4 4 4 4 4 4
向上 = 32:
04-07 21:45:27.979: D/random(15888): 16 15 15 14 15 15 15 24
04-07 21:45:28.329: D/random(15888): 23 23 23 24 24 24 24 21
04-07 21:45:28.549: D/random(15888): 22 20 20 20 20 21 21 21
04-07 21:45:28.849: D/random(15888): 31 31 31 31 31 31 29 29
04-07 21:45:29.329: D/random(15888): 27 28 28 28 26 26 26 26
但是对于 UP = 10,结果看起来是随机的,不是吗? --
04-07 21:47:02.189: D/random(15983): 8 4 1 9 6 6 4 2
04-07 21:47:02.639: D/random(15983): 7 5 3 0 7 5 2 0
04-07 21:47:02.999: D/random(15983): 3 9 6 4 1 8 6 3
04-07 21:47:03.379: D/random(15983): 5 4 1 8 6 3 0 8
04-07 21:47:03.669: D/random(15983): 5 1 8 6 3 3 1 8
04-07 21:47:03.989: D/random(15983): 3 3 1 4 1 8 6 3
04-07 21:47:04.269: D/random(15983): 6 6 3 1 8 5 3 0
所以我只有一个问题:任何人都知道发生了什么以及为什么?为什么nextInt(2^N) 得到的结果是非随机的,而任何其他参数得到的结果都很好?
===================================
更新。 cmets 中的人说,在桌面上 JVM 结果是随机的,独立于作为 nextInt() 参数传递的数字。那么所描述的行为是否仅适用于 Android?
更新 2。 标记为最适合此问题的答案,尤其是下面的讨论,对所发生的情况给出了非常清楚的解释。
【问题讨论】:
-
"但是每次由 Random() 构造函数创建新的 Random 实例时,Java 都会更改静态种子数" 这似乎与您的数据相矛盾。
-
@LouisWasserman 我添加了一段源代码,表明它确实如此......我不知道为什么当 2^N 放在 nextInt() 上时会发生这种情况......对于其他数字,一切看起来很好。
-
如果我没记错的话,Random 使用两个种子。一个是所有实例的常量种子,另一个是启动时间的
AtomicLong -
无法在桌面 JVM 上重现,具有任何
UP值。 -
@Salauyou 你在什么环境下运行它?我运行了您的代码,并预计 UP 各种值的伪随机分布,包括 4、8、32 等