Czy można współużytkować jedną instancję Random
klasy między wieloma wątkami? A nextInt(int)
zwłaszcza dzwonić z wielu wątków?
java.util.concurrent.ThreadLocalRandom
.
Czy można współużytkować jedną instancję Random
klasy między wieloma wątkami? A nextInt(int)
zwłaszcza dzwonić z wielu wątków?
java.util.concurrent.ThreadLocalRandom
.
Odpowiedzi:
Jest bezpieczny dla wątków w tym sensie, że nadal generuje liczby losowe, gdy jest używany przez wiele wątków.
Implementacja Sun / Oracle JVM używa synchronizacji i AtomicLong jako materiału siewnego, aby poprawić spójność między wątkami. Ale wydaje się, że nie jest to gwarantowane na wszystkich platformach w dokumentacji.
Nie napisałbym Twojego programu, aby wymagał takiej gwarancji, zwłaszcza że nie możesz określić kolejności w jakiej nextInt()
będzie wywoływany.
Jest bezpieczny dla wątków, chociaż nie zawsze.
Więcej informacji można znaleźć pod adresem http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070 .
Zgodnie z dokumentacją Math.random () gwarantuje, że jest bezpieczny dla wielu wątków. Ale klasa Random nie. Zakładam, że będziesz musiał to sam zsynchronizować.
Tak, Random jest bezpieczny dla wątków. nextInt()
sposób wymaga chronionego next(int)
metody przy wykorzystaniu AtomicLong seed, nextseed
(atomowe długości), aby wygenerować następny nasion. AtomicLong
służy do zabezpieczenia nici podczas wytwarzania nasion.
Jak powiedziano, jest to zapis wątków, ale rozsądne może być użycie java.util.concurrent.ThreadLocalRandom
zgodnie z tym artykułem (link martwy). ThreadLocalRandom jest również podklasą Random, więc jest kompatybilny wstecz.
W artykule związane z nim porównała wyniki profilowania różnych klas Losowo:
java.util.Random
,java.util.concurrent.ThreadLocalRandom
ijava.lang.ThreadLocal<java.util.Random>
. Wyniki pokazały, że użycie ThreadLocalRandom jest najbardziej wydajne, a następnie ThreadLocal i najgorzej działającego samego Random.
Nie ma powodu, dla którego wiele wątków nie może używać tego samego Random. Jednakże, ponieważ klasa nie jest jawnie bezpieczna dla wątków i utrzymuje sekwencję liczb pseudolosowych za pośrednictwem ziarna. Wiele wątków może mieć tę samą liczbę losową. Byłoby lepiej, gdybyśmy utworzyli wiele Randomów dla każdego wątku i użyli ich inaczej.
EDYCJA : Właśnie zauważyłem, że implementacja Sun używa AtomicLong, więc myślę, że jest bezpieczna dla wątków (jak również zauważył Peter Lawrey (+1)).
EDIT2 : OpenJDK używa również AtomicLong jako materiału siewnego. Jak powiedzieli inni, nadal nie warto na tym polegać.
Oto, jak poradziłem sobie z problemem, nie zakładając, że Random używa zmiennych atomowych. W currentTime * thread id
przyszłości może zderzyć się losowo, jeśli będzie równy, ale jest to wystarczająco rzadkie dla moich potrzeb. Aby naprawdę uniknąć kolizji, możesz kazać każdemu żądaniu czekać na unikalny znacznik czasu zegara.
/**
* 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());
}
};
(24*60*60*1000)
część ma znaczenie?
(24*60*60*1000)
Było tak, że wątek z ID 12
w xxxxxxxxxx045
Millis nie wysiewa się tak samo jak nitka 22
w xxxxxxxxxx035
Millis. Jednak nie mam żadnego dobrego powodu, by zakładać, że identyfikatory wątków są przyrostowe i nie ma powodu, by sądzić, że jutro tworzę wątki w bardziej losowych momentach niż dzisiaj. Uprościłem teraz algorytm i zaktualizowałem opis, aby zidentyfikować niedociągnięcie.
Random
Klasa nie jest skonfigurowane do jednej instancji do wykorzystania w wielu wątkach. Oczywiście, jeśli to zrobiłeś, prawdopodobnie zwiększysz prawdopodobieństwo uzyskania nieprzewidywalnych i bliższych losowych liczb. Ale ponieważ jest to generator pseudolosowy, nie rozumiem, dlaczego miałbyś udostępniać instancję. Czy jest jakiś bardziej szczegółowy wymóg?