在Java中生成随机数的快速高效方法

时间:2012-03-10 19:02:34

标签: java random

我正在编写一个生成大量随机数的多线程Java程序。

其他详细信息: 这些数字用于创建0-99的随机数列表,不重复,并且列表中存在0-99范围内的每个数字(换句话说,列表包含0-99范围内的100个唯一元素)

生成随机数[事情已经尝试过了!]

  1. 我有一个0-100的数字列表。我生成一个随机数,并将其用作索引,用于弹出ArrayList中的元素。
  2. 我使用了Collections.shuffle()
  3. 以下是方法1的代码:

    ArrayList<Integer> arr = new ArrayList<Integer>(); 
    for (int i = 0; i < N; i++){
     arr.add(i, i);
    }
    
    for(int i=0; i<N; i++){
      int indx = rand.nextInt(arr.size());
      res.add(arr.get(indx));
      arr.remove(indx);
    }
    

    对于第二种方法,我用for替换了第二个Collections.shuffle(arr)循环。

    由于生成随机数列表是我算法中最昂贵的部分,我想优化它。这让我想到了问题:

    1. 生成随机数的最快方法是什么?
    2. 如上所述生成随机数列表的最快方法是什么?
    3. PS:

      1. 我发现Collections.shuffle()比第一种方法慢
      2. 有人建议我使用rngd从Unix中的硬件生成随机数。有人曾尝试过这个吗?你是怎么做到的?

4 个答案:

答案 0 :(得分:7)

我认为Collections.shuffle()的问题是使用默认的Random实例,它是一个线程安全的单例。你说你的程序是多线程的,所以我可以想象Random中的同步是一个瓶颈。

如果您喜欢使用Java 7,只需使用ThreadLocalRandom即可。仔细观察,有shuffle()版本明确地采用Random实例:

Collections.shuffle(arr, threadLocalRandom);

其中threadLocalRandom仅创建一次。

在Java 6上,您只需为每个线程创建一个Random个实例。请注意,除非每次都能提供随机种子,否则不应每次运行创建Random的新实例。

答案 1 :(得分:1)

部分问题可能是Integer装箱和拆箱的开销。您可能会发现直接在int[]重新实现Fisher-Yates shuffle很有帮助。

答案 2 :(得分:0)

我的方法是使用Math.random()方法生成数字,如示例here中所示,并通过静态init块初始化列表,如下所示:

private static List<int> list = new ArrayList<int>();
static {
  for(int i = 0; i < 100; i++) {
    // randomize number
    list.add(number);
  }
}

希望这有帮助,玩得开心!

答案 3 :(得分:0)

调整n个元素的数组a(索引0..n-1):

for i from n − 1 downto 1 do
       j ← random integer with 0 ≤ j ≤ i
       exchange a[j] and a[i]

检查Fischer and Yattes算法。