ランダムクラスはスレッドセーフですか?


110

Random複数のスレッド間でクラスの1つのインスタンスを共有することは有効ですか?そしてnextInt(int)、特に複数のスレッドから呼び出すには?


@Bala R、いいえ、C#のRandomオブジェクトではなく、Javaについて話しています。
ブハケシンディ

おっとっと。すみません、その部分を逃しました。
Bala R

ランダムを使用してマルチスレッド環境で数値を取得するように注意すると、悪い結果が生じる可能性があります。
マックスシュミット2011

14
さらなる読者のために:1.7という名前の新しいクラスがありjava.util.concurrent.ThreadLocalRandomます。
Jin Kwon、

java.util.Randomの同時使用における競合に注意してください。
Vadzim

回答:


66

複数のスレッドで使用された場合でも乱数を生成するという意味で、スレッドセーフです。

Sun / Oracle JVMの実装では、同期されたAtomicLongをシードとして使用して、スレッド間の一貫性を向上させます。ただし、ドキュメント内のすべてのプラットフォームで保証されているようには見えません。

特にnextInt()呼び出される順序を決定できないため、このような保証を要求するようにプログラムを作成することはありません。


69
Java 7のドキュメントに「java.util.Randomのインスタンスはスレッドセーフである」という保証が追加されました。docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R



7

はい、ランダムはスレッドセーフです。このnextInt()メソッドは、(atomic long)を使用して次のシードを生成する保護されたnext(int)メソッドを呼び出しますAtomicLong seed, nextseedAtomicLongシード生成時のスレッドセーフのために使用されます。


6

言ったように、それはスレッドの保存ですがjava.util.concurrent.ThreadLocalRandomこの記事(リンクデッド)に従って使用するのが賢明かもしれません。ThreadLocalRandomはRandomのサブクラスでもあるため、下位互換性があります。

記事は異なるランダムクラスの比較プロファイリング結果をリンク:java.util.Randomjava.util.concurrent.ThreadLocalRandomjava.lang.ThreadLocal<java.util.Random>。結果は、ThreadLocalRandomの使用が最もパフォーマンスが高く、続いてThreadLocalとRandom自体のパフォーマンスが最も低いことを示しています。


4

複数のスレッドがすべて同じランダムを使用できないわけではありません。ただし、クラスは明示的にスレッドセーフではなく、シードを介して一連の疑似乱数を維持するためです。複数のスレッドが同じ乱数になる可能性があります。スレッドごとに複数のランダムを作成し、それらを異なる方法でシードすることをお勧めします。

編集:私はSunの実装がAtomicLongを使用していることに気付いたので、それはスレッドセーフであると思います(Peter Lawrey(+1)によっても指摘されています)。

EDIT2:OpenJDKもシードにAtomicLongを使用します。他の人が言っているように、これに頼るのはまだ良くありません。


3

ランダムがアトミック変数を使用すると仮定せずに問題に対処する方法を次に示します。それが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());
    }
};

アップ!Q:(24*60*60*1000)一部は重要ですか?
ジンクォン

1
ええ、それは汚い修正でした。(24*60*60*1000)IDとスレッドほどだった12xxxxxxxxxx045ミリ秒をスレッドと同じ播種されませんでした22ではxxxxxxxxxx035ミリ秒。ただし、スレッドIDがインクリメンタルであると想定する正当な理由はなく、明日よりもランダムな時間にスレッドを作成していると考える正当な理由はありません。ここでalgを簡略化し、説明を更新して欠点を特定しました。
Ryan

0

Randomクラスは、複数のスレッドで使用される1つのインスタンスに設定されていません。もちろん、これを行った場合、予測不能になり、乱数に近づく可能性が高くなります。しかし、これは疑似ランダムジェネレーターであるため、インスタンスを共有する必要がある理由がわかりません。より具体的な要件はありますか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.