Ist der Thread einer zufälligen Klasse sicher?

110

Ist es gültig, eine Instanz der RandomKlasse für mehrere Threads freizugeben? Und nextInt(int)insbesondere aus mehreren Threads aufzurufen ?

Shcheklein
quelle
@Bala R, nein, wir sprechen nicht über das zufällige Objekt von C #, sondern über das von Java.
Buhake Sindi
Hoppla. Entschuldigung, ich habe diesen Teil verpasst.
Bala R
Wenn Sie Random verwenden, um Zahlen in einer Multithread-Umgebung zu erhalten, können Sie schlechte Ergebnisse erzielen. Möglicherweise spielt es keine Rolle, aber wenn Sie einige Simulationen durchführen, ist es gut zu wissen.
Maxence SCHMITT
14
Für weitere Leser: Es gibt eine neue Klasse mit dem Namen 1.7 java.util.concurrent.ThreadLocalRandom.
Jin Kwon

Antworten:

66

Es ist threadsicher in dem Sinne, dass es bei Verwendung durch mehrere Threads immer noch Zufallszahlen generiert.

Die Sun / Oracle JVM-Implementierung verwendet synchronisiert und AtomicLong als Startwert, um die Konsistenz zwischen den Threads zu verbessern. Es scheint jedoch nicht für alle Plattformen in der Dokumentation garantiert zu sein.

Ich würde Ihr Programm nicht schreiben, um eine solche Garantie zu verlangen, zumal Sie die Reihenfolge, in der nextInt()aufgerufen wird, nicht bestimmen können .

Peter Lawrey
quelle
69
In den Java 7-Dokumenten wurde eine Garantie hinzugefügt: "Instanzen von java.util.Random sind threadsicher." docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R
8

Gemäß der Dokumentation garantiert Math.random () , dass es für die Verwendung durch mehrere Threads sicher ist. Die Zufallsklasse tut dies jedoch nicht. Ich würde davon ausgehen, dass Sie das selbst synchronisieren müssen.

Vincent Mimoun-Prat
quelle
7

Ja, Random ist threadsicher. Die nextInt()Methode ruft die geschützte next(int)Methode auf, die AtomicLong seed, nextseed(atomar lang) verwendet, um einen nächsten Startwert zu generieren. AtomicLongwird zur Gewindesicherheit bei der Samenerzeugung verwendet.

Buhake Sindi
quelle
6

Wie gesagt, es ist Thread-sicher, aber es kann ratsam sein, java.util.concurrent.ThreadLocalRandomgemäß diesem Artikel zu verwenden (Link tot). ThreadLocalRandom ist ebenfalls eine Unterklasse von Random und daher abwärtskompatibel.

Der Artikel verlinkte verglichenen Profilierungs Ergebnisse der verschiedenen Zufalls Klassen: java.util.Random, java.util.concurrent.ThreadLocalRandom und java.lang.ThreadLocal<java.util.Random>. Die Ergebnisse zeigten, dass die Verwendung von ThreadLocalRandom am leistungsfähigsten ist, gefolgt von ThreadLocal und Random mit der schlechtesten Leistung.

Seyfahni
quelle
4

Es gibt keinen Grund, warum mehrere Threads nicht alle denselben Zufall verwenden können. Da die Klasse jedoch nicht explizit threadsicher ist und eine Folge von Pseudozufallszahlen über den Startwert beibehält. Mehrere Threads können dieselbe Zufallszahl haben. Es wäre besser, mehrere Zufälle für jeden Thread zu erstellen und sie unterschiedlich zu setzen.

EDIT : Ich habe gerade bemerkt, dass die Sun-Implementierung AtomicLong verwendet, also denke ich, dass dies Thread-sicher ist (wie auch von Peter Lawrey (+1) bemerkt).

EDIT2 : OpenJDK verwendet auch AtomicLong für den Startwert. Wie andere gesagt haben, ist es immer noch nicht gut, sich darauf zu verlassen.

alpian
quelle
3

Hier ist, wie ich mit dem Problem umgegangen bin, ohne anzunehmen, dass Random atomare Variablen verwendet. Es kann immer noch zufällig kollidieren, wenn currentTime * thread ides irgendwann in der Zukunft gleich ist, aber das ist selten genug für meine Bedürfnisse. Um Kollisionsmöglichkeiten wirklich zu vermeiden, kann jede Anforderung auf einen eindeutigen Zeitstempel warten.

/**
 * 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());
    }
};
Ryan
quelle
Oben! F: Ist ein (24*60*60*1000)Teil von Bedeutung?
Jin Kwon
1
Ja, das war eine schmutzige Lösung. Das (24*60*60*1000)war so, dass ein Thread mit der ID 12bei xxxxxxxxxx045Millis nicht wie ein Thread 22bei xxxxxxxxxx035Millis ausgesät wurde. Ich habe jedoch keinen guten Grund anzunehmen, dass Thread-IDs inkrementell sind, und es gibt keinen guten Grund zu der Annahme, dass ich morgen zu mehr zufälligen Zeiten als heute Threads erstelle. Ich habe die Alge jetzt vereinfacht und die Beschreibung aktualisiert, um das Manko zu identifizieren.
Ryan
0

Die RandomKlasse ist nicht für eine Instanz eingerichtet, die in mehreren Threads verwendet werden soll. Wenn Sie dies tun, erhöhen Sie natürlich wahrscheinlich die Wahrscheinlichkeit, unvorhersehbar zu werden und Zufallszahlen näher zu kommen . Da es sich jedoch um einen Pseudozufallsgenerator handelt, kann ich nicht erkennen, warum Sie eine Instanz gemeinsam nutzen müssen. Gibt es eine spezifischere Anforderung?

Java Drinker
quelle