Czy wątek klasy Random jest bezpieczny?

110

Czy można współużytkować jedną instancję Randomklasy między wieloma wątkami? A nextInt(int)zwłaszcza dzwonić z wielu wątków?

Shcheklein
źródło
@Bala R, nie, nie mówimy o obiekcie Random w języku C #, ale o Javie.
Buhake Sindi
ups. przepraszam przegapiłem tę część.
Bala R
Dbanie o użycie Random w celu uzyskania liczb w środowisku wielowątkowym może dać złe wyniki. Może to nie ma znaczenia, ale jeśli wykonujesz jakieś symulacje, dobrze jest wiedzieć.
Maxence SCHMITT
14
Dla dalszych czytelników: istnieje nowa klasa o nazwie 1.7 java.util.concurrent.ThreadLocalRandom.
Jin Kwon

Odpowiedzi:

66

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.

Peter Lawrey
źródło
69
W dokumentacji Java 7 dodano gwarancję: „Instancje java.util.Random są bezpieczne dla wątków”. docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R,
8

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ć.

Vincent Mimoun-Prat
źródło
7

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. AtomicLongsłuży do zabezpieczenia nici podczas wytwarzania nasion.

Buhake Sindi
źródło
6

Jak powiedziano, jest to zapis wątków, ale rozsądne może być użycie java.util.concurrent.ThreadLocalRandomzgodnie 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 i java.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.

seyfahni
źródło
4

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ć.

alpejski
źródło
3

Oto, jak poradziłem sobie z problemem, nie zakładając, że Random używa zmiennych atomowych. W currentTime * thread idprzyszł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());
    }
};
Ryan
źródło
W górę! P: czy (24*60*60*1000)część ma znaczenie?
Jin Kwon
1
Tak, to była brudna sprawa. (24*60*60*1000)Było tak, że wątek z ID 12w xxxxxxxxxx045Millis nie wysiewa się tak samo jak nitka 22w xxxxxxxxxx035Millis. 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.
Ryan
0

RandomKlasa 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?

Java Drinker
źródło