3

私は、Javaでの乱数生成とマルチスレッドの概念を学んでいます。

アイデアは、特定のミリ秒で範囲 1000 の繰り返し乱数を生成しないことです (マルチスレッドの方法で 50 以下のデータがミリ秒で処理されることを考慮してください)。そのため、特定の時間に生成された乱数のリストは一意です。特定のミリ秒でいくつかの繰り返し乱数を生成することになっているので、何か考えを教えてください(また、かなりの確率があります)。

私は失敗した次のことを試しました。

Random random = new Random(System.nanoTime());
double randomNum = random.nextInt(999);

///

int min=1; int max=999;
double randomId = (int)Math.abs(math.Random()* (max - min + 1) + min);

///

Random random = new Random(System.nanoTime()); // also tried new Random();
double randomId = (int)Math.abs(random.nextDouble()* (max - min + 1) + min);

生成されているタイムスタンプを追加していると、マルチスレッド環境で、5000 以上の一意のデータに対して生成されている (2 ~ 4 回) 同じ ID (約 8 ~ 10) が表示されます。

4

3 に答える 3

4

まず、次のようnew Random()に見えるため、を使用する必要があります(詳細は Java のバージョンによって異なります)。

 public Random() { this(++seedUniquifier + System.nanoTime()); }
 private static volatile long seedUniquifier = 8682522807148012L;

つまり、同じ結果の異なるスレッドが異なるシードを取得することを既に利用nanoTime() て確認していますが、そうではありません。nanoTime()new Random(System.nanoTime())

(編集: Pyranja は、これは Java 6 のバグであると指摘しましたが、Java 7 では修正されています:

public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

private static long seedUniquifier() {
    // L'Ecuyer, "Tables of Linear Congruential Generators of
    // Different Sizes and Good Lattice Structure", 1999
    for (;;) {
        long current = seedUniquifier.get();
        long next = current * 181783497276652981L;
        if (seedUniquifier.compareAndSet(current, next))
            return next;
    }
}

private static final AtomicLong seedUniquifier
    = new AtomicLong(8682522807148012L);

)

次に、1 から 1000 までの乱数を 50 個生成すると、誕生日のパラドックスのおかげで、いくつかの数字が同じになる確率が非常に高くなります。

第 3 に、一意の ID だけが必要な場合はAtomicInteger、乱数の代わりにカウンターを使用できます。または、最初にランダムな部分が必要な場合は、一意性を保証するためにカウンターも追加します。

于 2013-10-01T09:11:17.583 に答える
2

このクラスを使用すると、範囲全体が使用されるまで、特定の範囲から非反復値を取得できます。範囲が使用されると、再初期化されます。

クラスには簡単なテストが付属しています。

クラスをスレッドセーフにしたい場合は、宣言に追加synchronizedするだけです。nextInt()

次に、シングルトン パターンまたは静的変数のみを使用して、複数のスレッドからジェネレーターにアクセスできます。そうすれば、すべてのスレッドが同じオブジェクトと同じ一意の ID プールを使用します。

public class NotRepeatingRandom {
    int size;
    int index;
    List<Integer> vals;
    Random gen = new Random();

    public NotRepeatingRandom(int rangeMax) {
      size = rangeMax;
      index = rangeMax; // to force initial shuffle
      vals = new ArrayList<Integer>(size);
      fillBaseList();
    }

    private void fillBaseList() {
      for (int a=0; a<size; a++) {
        vals.add(a);
      }
    }

    public int nextInt() {
      if (index == vals.size()) {
          Collections.shuffle(vals);
          index = 0;
      }
      int val = vals.get(index);
      index++;      
      return val;
    }

    public static void main(String[] args) {
        NotRepeatingRandom gen = new NotRepeatingRandom(10);
        for (int a=0; a<30; a++) {
            System.out.println(gen.nextInt());
        }
    }
}
于 2013-10-01T09:04:56.960 に答える