2011-01-25 82 views
4

我正在使用一个调用新Random()。nextLong()生成nonces的OAuth库,但它在异步调用上会生成相同的nonce。我已经缩小到线程Random.nextLong()每隔一段时间返回相同的确切数字。Java线程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(); 
    } 
} 

}

+0

你可以发布您的代码 – 2011-01-25 19:25:04

+0

见的SecureRandom - http://download.oracle.com/javase/7/docs/api/java/security/SecureRandom.html – jjnguy 2011-01-25 19:26:29

+0

这实在不应该发生,尤其不应该因为它使用System.nanoTime和一个易变的seedUniquifier。 – maaartinus 2011-01-25 19:31:18

回答

4

你可能不希望创建随机的,每次一个新实例。而是有一个全球性的。

2

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

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

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

如果您创建相同毫秒内随机的对象,他们将有值的顺序相同。

通常情况下,您希望在所有不同的线程中共享一个Random对象,以避免这种问题。

1

虽然我不是立即熟悉底层实现Random,如果我猜我会想象呼吁new Random()委托给new Random(System.currentTimeMillis())。这为在不同时间实例化的Randoms提供了合理的Random序列。

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

0

我认为随机不是线程安全的,但它是。你应该只得到随机产生每2^48值相同的数字。

如前所述,Java 1.4和以前的版本有一个错误,两个Randoms可能会得到相同的种子。我建议你使用Java 6,或者将种子设置为独一无二的。

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

1

你应该真的使用SecureRandom,因为你正在使用它来处理与安全有关的事情。