Random
クラスの1つのインスタンスを複数のスレッド間で共有することは有効ですか?そして、特に複数のスレッドからnextInt(int)
を呼び出すには?
複数のスレッドで使用される場合でも乱数を生成するという意味で、スレッドセーフです。
Sun/Oracle JVM実装では、同期されたAtomicLongをシードとして使用して、スレッド間の一貫性を改善します。しかし、ドキュメントのすべてのプラットフォームで保証されているわけではありません。
特にnextInt()
が呼び出される順序を決定できないため、このような保証を要求するプログラムを作成しません。
常に安全とは限りませんでしたが、スレッドセーフです。
詳細については、 http://bugs.Sun.com/bugdatabase/view_bug.do?bug_id=636207 を参照してください。
ドキュメントによると、 Math.random() は、複数のスレッドが安全に使用できることを保証します。しかし、Randomクラスはそうではありません。その場合、それを自分で同期する必要があると思います。
はい、ランダムはスレッドセーフです。 nextInt()
メソッドは、_AtomicLong seed, nextseed
_(アトミックロング)を使用して次のシードを生成する保護されたnext(int)
メソッドを呼び出します。 AtomicLong
は、シード生成時のスレッドセーフに使用されます。
前述のように、これはスレッド保存ですが、 この記事 (リンク切れ)に従ってJava.util.concurrent.ThreadLocalRandom
を使用するのが賢明かもしれません。 ThreadLocalRandomはRandomのサブクラスでもあるため、下位互換性があります。
リンクされた記事では、異なるRandomクラスのプロファイル結果を比較しました:
Java.util.Random
、Java.util.concurrent.ThreadLocalRandom
、およびJava.lang.ThreadLocal<Java.util.Random>
。結果は、ThreadLocalRandomの使用が最もパフォーマンスが高く、続いてThreadLocalが使用され、ランダム自体が最もパフォーマンスが低いことを示しました。
複数のスレッドがすべて同じRandomを使用できない理由はありません。ただし、クラスは明示的にスレッドセーフではないため、シードを介して一連の擬似乱数を維持します。複数のスレッドが同じ乱数で終わる場合があります。スレッドごとに複数のランダムを作成し、それらを別々にシードする方が良いでしょう。
[〜#〜] edit [〜#〜]:Sunの実装がAtomicLongを使用していることに気付いたので、スレッドセーフであると推測します(Peter Lawrey(+1)にも記載されています) 。
EDIT2:OpenJDKは、シードにAtomicLongも使用します。他の人が言ったように、これに頼るのはまだ良くありません。
ここでは、Randomがアトミック変数を使用すると仮定せずに問題を処理しました。 currentTime * thread id
は将来のある時点で等しくなりますが、それは私のニーズにとってはまれです。衝突の可能性を完全に回避するために、各リクエストに一意のクロックタイムスタンプを待機させることができます。
/**
* Thread-specific random number generators. Each is seeded with the thread
* ID, so the sequence of pseudo-random numbers are unique between threads.
*/
private static ThreadLocal<Random> random = new ThreadLocal<Random>() {
@Override
protected Random initialValue() {
return new Random(
System.currentTimeMillis() *
Thread.currentThread().getId());
}
};
Random
クラスは、複数のスレッドで使用される1つのインスタンスに対して設定されていません。もちろん、これを行うと、予測不能になり、ランダム数値に近づく可能性が高くなります。しかし、それは擬似ランダムジェネレータなので、インスタンスを共有する必要がある理由がわかりません。より具体的な要件はありますか?