Java线程Random.nextLong()返回相同的数字

时间:2011-01-25 19:20:20

标签: java multithreading random thread-safety

我正在使用OAuth库来调用新的Random()。nextLong()来生成随机数,但是它会在异步调用中生成相同的随机数。我把它缩小到线程化,使Random.nextLong()每隔一段时间返回相同的确切数字。

有谁知道这是否是Java的已知限制?如果是这样,有没有人知道线程安全操作?

编辑:我正在使用Java 1.6

编辑:这是我用来测试我的大型应用程序中发生的事情的一个小程序。我跑了好几次,而且经常会这样,当时间相同的时候会出现相同的随机数。请原谅我的快速编程。

public class ThreadedRandom {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub

    new ThreadedRandom().run();
}

private RandomNumberGenerator _generator;

public ThreadedRandom()
{
    _generator = new RandomNumberGenerator();
}

public void run()
{
    Runnable r = new Runnable() {
        @Override public void run() {
            System.out.println(System.currentTimeMillis()+"\t"+_generator.gen());
        }
    };

    Thread t1, t2;

    t1 = new Thread(r);
    t2 = new Thread(r);

    t1.start();
    t2.start();
}

private class RandomNumberGenerator {

    Random random;
    public RandomNumberGenerator()
    {
        random = new Random();
    }

    public Long gen() {
        return new Random().nextLong();
    }
}

}

5 个答案:

答案 0 :(得分:4)

您可能不希望每次都创建一个新的Random实例。而是拥有全球性的。

答案 1 :(得分:2)

随机数不是真正随机的,它们是“伪随机的”并且它们需要“种子”值。如果使用相同的种子,将生成相同的伪随机值序列。

当您创建Random类的新实例时,您可以自己指定种子,也可以让系统为您选择一个种子。在Java中,默认种子是当前系统时间(以毫秒为单位),请参阅:

http://download.oracle.com/javase/1.4.2/docs/api/java/util/Random.html#Random%28%29

如果在同一毫秒内创建Random对象,它们将具有相同的值序列。

通常,您希望在所有不同的线程中共享一个Random对象,以避免出现此类问题。

答案 2 :(得分:1)

虽然我不是立即熟悉Random的基础实现,但如果我不得不猜测我会想象new Random()委托给new Random(System.currentTimeMillis())。这为在不同时间实例化的Randoms提供了一个相当不同的Random序列。

但是,由于您已经提到了异步调用,因此您的调用可能基本上同时执行。这意味着当线程调用库时,它们同时进入new Random()调用,并且Randoms获得相同的种子,因此它们将产生相同的随机序列。

答案 3 :(得分:1)

您应该使用SecureRandom,因为您将此用于安全性方面。

答案 4 :(得分:0)

我认为Random不是线程安全的,但确实如此。你应该只得到Random每2 ^ 48个值生成相同的数字。

正如已经注意到的,Java 1.4和之前的版本有两个Random可以获得相同种子的错误。我建议您使用Java 6,或者将种子设置为独一无二。

您还应注意Random使用48位种子。这意味着它将在2 ^ 48个值之后重复,并且仅产生2 ^ 48个唯一的长值。如果这对您来说是一个问题,请使用更昂贵的SecureRandom,但会生成所有可能的长值。