2014-04-30 7 views
17

Instanzen von java.util.Random sind threadsafe. Die gleichzeitige Verwendung der gleichen java.util.Random-Instanz über Threads hinweg kann jedoch zu Konflikten und folglich zu schlechter Leistung führen. Ziehen Sie stattdessen die Verwendung von ThreadLocalRandom in Multithread-Designs in Betracht.Zufällig über ThreadLocalRandom

Welche Art von Konkurrenz und damit schlechte Leistung? Kann mir bitte jemand, erklären Sie mir hier? Ich weiß nicht, welcher Algorithmus in Random und ThreadLocalRandom verwendet wird, was sie unterschiedlich macht.

Antwort

19

Dies könnte ein wenig helfen:

http://thoughtfuljava.blogspot.com/2012/09/prefer-threadlocalrandom-over-random.html


von der Quelle Zitat:

Normalerweise Zufallszahlen zu erzeugen, wir entweder gar eine Instanz von java.util erstellen. Zufälliges OR Math.random() - das intern eine Instanz von java.util.Random beim ersten Aufruf erstellt. In einer gleichzeitigen Anwendungen führt die Verwendung von oben zu Konflikten Probleme

Random ist Thread sicher für die Verwendung von mehreren Threads. Wenn jedoch mehrere Threads die gleiche Instanz von Random verwenden, wird dasselbe Seed von mehreren Threads gemeinsam verwendet. Dies führt zu Konflikten zwischen mehreren Threads und damit zu Leistungseinbußen.

ThreadLocalRandom ist Lösung für das obige Problem. ThreadLocalRandom hat eine zufällige Instanz pro Thread und schützt vor Konflikten.


Also, im Grunde eine zufällige Instanz pro Faden ermöglicht es Ihnen, auf dem Saatgut zu stoppen synchronisieren, die von allen Threads verwendet werden müssen.

+0

Wenn ich in jedem Thread eine neue Instanz von java.util.Random erstelle, führt das nicht zum selben Effekt wie die Verwendung von ThreadLocalRandom in jedem Thread? Oder verwenden alle Instanzen von java.util.Random den gleichen Seed? – Peter

+1

Ein Teil des Problems mit 'Random' ist, dass es unnötigerweise" synchronisiert "ist; selbst wenn Sie einen pro-Thread erstellen, ist dieser nicht so performant wie 'ThreadLocalRandom'. – dimo414

0

Nun, wenn Sie die gleiche Datenstruktur über mehrere Threads verwenden, muss es normalerweise synchronisiert werden. Das ist teuer und braucht Zeit. Ein ThreadLocalRandom muss nicht synchronisiert werden, da es nur von einem Thread verwendet wird.

0

Von ThreadLocalRandom API Dokument

A random number generator isolated to the current thread. Like the 
* global {@link java.util.Random} generator used by the {@link 
* java.lang.Math} class, a {@code ThreadLocalRandom} is initialized 
* with an internally generated seed that may not otherwise be 
* modified. When applicable, use of {@code ThreadLocalRandom} rather 
* than shared {@code Random} objects in concurrent programs will 
* typically encounter much less overhead and contention. Use of 
* {@code ThreadLocalRandom} is particularly appropriate when multiple 
* tasks (for example, each a {@link ForkJoinTask}) use random numbers 
* in parallel in thread pools. 

Zufalls mehrere Male/same Zufälliges Objekt erstellt werden kann, würde über mehrere Threads geteilt (aufgrund der Tatsache, sicher zu verwenden). Wie auch immer, das Erstellen mehrerer Instanzen/gleicher Ressourcenzugriffe durch mehrere Threads würde Overhead verursachen.

Anstatt Instanz pro Thread zu erstellen und die Ressource in ThreadLocal zu verwalten, wäre perfekter. Da die Instanz nicht über mehrere Threads hinweg geteilt wird. und es gibt keinen öffentlichen Konstruktor, Sie sollten die Factory-Methode verwenden, um sie zu erhalten.

Ich würde sagen, es ist nur Factory of Random Objects, die Instanz pro Thread verwaltet/zwischenspeichert.

0

Eine zufällige Instanz kann nur jeweils einem Thread eine Zufallszahl bereitstellen. Wenn also viele Threads gleichzeitig Zufallszahlen von dieser Instanz anfordern, werden alle Threads langsamer.

Auf der anderen Seite würde jeder Thread seine eigene ThreadLocalRandom-Instanz haben, so dass keine Threads bei der Anforderung einer Zufallszahl blockiert würden.

1

Die Kernalgorithmen sind im Wesentlichen die gleichen. Der ThreadLocalRandom verwendet das Java ThreadLocal-Konstrukt, um eine neue zufällige Variable für jeden Thread zu erstellen. Dies garantiert, dass die Aufrufe von jedem Thread niemals mit jedem Konflikt kollidieren (keine Konkurrenz).

Werfen Sie einen Blick auf diese Linie Zufälliges zum Vergleich:

} while (!seed.compareAndSet(oldseed, nextseed)); 

Wenn Sie für einen nächsten Wert fragen, Zufall nimmt den alten Wert und erzeugt einen neuen Wert. Es verwendet dann die AtomicLong.compareAndSet-Funktion, um den neuen Wert nur dann festzulegen, wenn der alte Wert immer noch der alte Wert ist. Wenn ein anderer Thread den Wert geändert hat, wird die Schleife erneut ausgeführt (und wieder, bis sie die einzige Schleife ist, die den Wert in einer Zufallszahlengenerierung abruft und setzt). Somit sind mögliche Konflikte und somit mögliche Auswirkungen auf die Leistung möglich.

Der ThreadLocalRandom benötigt keine atomaren Funktionen und thread-sicheren Operationen/Sperren, da garantiert kein Konflikt entsteht.

Es gibt einige Kompromisse, über die Sie nachdenken sollten. Die Verwendung von einem Zufallsgenerator ermöglicht einen Zufallszahlengenerator, der sehr nützlich ist, wenn Sie einen einzelnen Startwert für Ihre Anwendung verwenden möchten. Wenn Sie gelegentlich nur Random aufrufen, sodass Konflikte wahrscheinlich "selten" sind (nicht der Normalfall), müssen Sie sich keine Gedanken über Konflikte machen, und die kleinen individuellen Auswirkungen auf die Leistung spielen keine Rolle. Wenn Sie Hunderte von Sekunden pro Sekunde über mehrere Threads hinweg aufrufen, möchten Sie ThreadLocalRandom eindeutig verwenden.

1

Es gibt einige Probleme mit ThreadLocalRandom, das Sie nicht steuern können, den anfänglichen Startwert. Ich finde auch nicht irgendwo eine funktionierende Set-Seed-Methode.

Es sollte beachtet werden, dass es Anstoßes ist, wenn mehrere Threads verwenden Math.random(), da sie Zufall eine gemeinsame Instanz der Klasse unter der Haube Zugang wird es bei der Verwendung ThreadLocalRandom ist eine Alternative, die auch das löst Samenproblem.

ThreadLocalRandom verwendet einen im Thread gespeicherten Seed. Und sie entschieden , um den anfänglichen Samen für Sie zu tun, ohne irgendwelche Mittel, um es zu kontrollieren. Sie können genauso gut erstellen Sie Ihre eigene Instanz von Random und verwenden Sie es in einer lokalen Thread-Mode. Also wenn Sie folgendes tun:

/* my thread */ 
rnd = new Random(my_seed); 
/* use rnd */ 

Sie werden auch keine Konkurrenz sehen. Und mit dem gleichen Samen erhalten Sie reproduzierbare zufällige Sequenzen, die beim Testen helfen können. Wenn Sie mehrere Threads haben können Sie Samen über diese Threads verteilen. Es sollte Algorithmen geben, um gute Abstandssamen zu erzeugen.