使用当前时间与无时间的随机数发生器

时间:2015-08-28 17:57:00

标签: java random

我想了解使用带有System.currentTimeMillis()的随机数生成器作为种子和使用默认构造函数之间的区别。也就是说,这有什么区别:

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

和此:

Random rand = new Random();

我知道这些数字是伪随机的,但我还没有完全理解细节,以及它们是如何产生的,在随机性和随机性之间。当当前时间用作种子时,以及使用默认构造函数时获取。

3 个答案:

答案 0 :(得分:6)

提供自己的种子对于您有意希望多次生成相同的伪随机值序列的模拟非常有用。但是,一般情况下,使用默认构造函数也是如此。

使用默认构造函数时,the docs说:

  

此构造函数将随机数生成器的种子设置为非常可能与此构造函数的任何其他调用不同的值。

换句话说,它在内部生成自己的种子。细节取决于所使用的特定Java实现。我见过的一个实现有:

private static volatile long seedBase = 0;

public Random() {
    setSeed(System.nanoTime() + seedBase);
    ++seedBase;
}

随机性的实际质量不会改变。如果您关心随机序列的质量,您还可以使用java.security.SecureRandom,它具有更好的加密行为。 (参见,例如,this thread。)

答案 1 :(得分:5)

如果您希望在运行之间随机序列相同,则可以指定种子。通常你不希望这种情况发生,所以你为每次运行使用不同的种子,System.currentTimeMillis()是常用的合理种子。如果您正面临多线程,多线程将同时初始化RNG,您可能希望避免使用System.currentTimeMillis()并让Java使用自己的初始化。

答案 2 :(得分:1)

如果查看Random的默认构造函数的实现,可以看到它在内部使用System.nanoTime()。此外,它使用种子' uniquifier'使随后的种子更加鲜明。但是,这需要访问static final AtomicLong。因此,如果您有一个高度并发的应用程序,其中许多线程正在构造Random个实例,那么最好不使用默认构造函数来避免对种子生成的争用。如果你想保证两个线程永远不能获得相同的种子,你应该采用默认的构造函数。 实际上,在99%的案例中,这与你所采用的变体无关。

正如Ted Hopp所说,默认构造函数的行为取决于具体的JDK实现,并且在Java版本之间也有所不同。

另请参阅Contention in concurrent use of java.util.Random了解Random类的其他争用问题。

相关问题