2 つのスレッドで 2 つの乱数ジェネレーターをほぼ同時に初期化していますが、2 つのジェネレーターの動作がまったく異なるようにしたいと考えています。Random.nextInt(7)
私は非常に頻繁に 2 つのジェネレーターを次々と呼び出します。System.currentTimeMillis()
私のコンピューターは非常に高速で、2 つのジェネレーターから得られる数値が同じになる可能性が高いため、使用はお勧めできません。それでRandom
、それらが次々と呼び出されても、動作が異なるように設定する方法はありますか? ソリューションをクロスプラットフォーム互換にしたいので、読み取り元などのプラットフォーム固有のアイデア/dev/random
は受け入れられません。手伝ってくれてありがとう。
5 に答える
1 つの方法: UUID (GUID) が long に変換された (ハッシュされた? しかし、おそらく単なるキャストではない) ランダム インスタンスをシードします。
他の回答は、ハードウェアの速度に応じて適切なnanoTimeを使用することを提案していますが、私は UUID ルートを好みます。
を使用SecureRandom
して、2 つの乱数ジェネレーターのシードを生成できます。プラットフォーム固有のエントロピー ソースを使用できるサービス プロバイダー インフラストラクチャを使用するため、それが利用可能なシステムでは/dev/random
、コードでエントロピーを気にする必要なくエントロピーを取得できます。別の回答で言及されているUUIDは、少なくともOpenJDK 7.6では、そのようなソースから生成されます。
とはいえ、Java 7 以降、複数のスレッドで PRNG を使用する推奨される方法はThreadLocalRandom
. よくわかりませんが、ここでの主な目標は、シードの問題ではなく、同期のオーバーヘッドを回避することであるように思えます。少なくとも OpenJDK 7.6 では、コンストラクターはデフォルトのRandom
コンストラクターを使用します。これは、静的変数の現在の値と組み合わせて、高解像度のシステム時刻 (ナノ秒単位で指定されますが、必ずしも実際の解像度である必要はありません) を使用します。Random
後者は、システム クロックの同じティック中に作成されたインスタンスに対しても異なるシードを保証するため、デフォルトのコンストラクターを使用してインスタンスを単純に構築する場合でも、元の問題は解消されるはずです。
この一意化は、バグ レポート #6937857に対応して、2010 年に導入されました。レポートはJava 7に対して報告され、Java 7でも修正されましたが、mercurialリポジトリによると、この変更は最初にリリースに含まれるべきでした.jdk7-b94
which を使用System.nanoTime()
すると、両方のスレッドが同じシードを持つ可能性を減らすことができます。
または、スレッドセーフなユーティリティ クラスを作成して乱数オブジェクトを取得し、新しいインスタンスごとに異なるシードを使用するようにします。
また、各スレッドに数値 IDをスレッド名として割り当て、それをシードに追加することもできます
何もしないでください。できます!
これは java.util.Random のコードです:
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
名前が示すように、seedUniquifier
はシードを一意にします。シングルスレッドとマルチスレッドの両方で機能します。
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;
}
}
System.nanoTime()
の代わりに を使用できますSystem.currentTimeMillis()
。
2 番目のスレッドの作成を 30 ミリ秒遅らせるだけで、nanoTime() がスレッド 1 の nanoTime() とランダムに異なります。
したがって、あなたの質問には実用的な見方が 1 つあります。このビュー nanoTime() については、私は十分だと考えています。
もう 1 つの見方は、軍用の安全な暗号化に対するより理論的なものです。そこでは、物理的ランダム性 (ランダム レジスタ) を使用する特別なハードウェアを使用したいと考えています。しかし、それはあなたの意図ではありません。