Il thread di classe casuale è sicuro?


110

È valido condividere un'istanza della Randomclasse tra più thread? E nextInt(int)in particolare per chiamare da più thread?


@Bala R, no, non stiamo parlando dell'oggetto Random di C # ma di Java.
Buhake Sindi

oops. mi dispiace aver perso quella parte.
Bala R

Usare Random per ottenere numeri in un ambiente multithread può darti cattivi risultati, forse non importa, ma se stai facendo delle simulazioni è bene saperlo.
Maxence SCHMITT

14
Per ulteriori lettori: c'è una nuova classe con 1.7 denominata java.util.concurrent.ThreadLocalRandom.
Jin Kwon

Risposte:


66

È thread-safe nel senso che genererà comunque numeri casuali quando viene utilizzato da più thread.

L'implementazione Sun / Oracle JVM utilizza sincronizzato e AtomicLong come seme per migliorare la coerenza tra i thread. Ma non sembra essere garantito su tutte le piattaforme nella documentazione.

Non scriverei il tuo programma per richiedere una tale garanzia, soprattutto perché non puoi determinare l'ordine in cui nextInt()verrà chiamato.


69
È stata aggiunta una garanzia nella documentazione di Java 7: "Le istanze di java.util.Random sono threadsafe". docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R


8

Secondo la documentazione, Math.random () garantisce che sia sicuro per l'uso da più thread. Ma la classe Random no. Presumo che quindi dovrai sincronizzarlo da solo.


7

Sì, Random è thread-safe. il nextInt()metodo chiama il next(int)metodo protetto che usa AtomicLong seed, nextseed(atomic long) per generare un seme successivo. AtomicLongviene utilizzato per la sicurezza del thread sulla generazione del seme.


6

Come detto, è un thread save, ma potrebbe essere saggio usarlo java.util.concurrent.ThreadLocalRandomsecondo questo articolo (link morto). ThreadLocalRandom è anche una sottoclasse di Random, quindi è compatibile con le versioni precedenti.

L'articolo collegato confrontato profilazione risultati delle diverse classi casuali: java.util.Random, java.util.concurrent.ThreadLocalRandom e java.lang.ThreadLocal<java.util.Random>. I risultati hanno mostrato che l'utilizzo di ThreadLocalRandom è più performante, seguito da ThreadLocal e dallo stesso Random con le peggiori prestazioni.


4

Non c'è motivo per cui più thread non possano utilizzare tutti lo stesso Random. Tuttavia, poiché la classe non è esplicitamente thread-safe e mantiene una sequenza di numeri pseudo-casuali tramite il seme. Più thread possono finire con lo stesso numero casuale. Sarebbe meglio creare più Random per ogni thread e seminarli in modo diverso.

EDIT : Ho appena notato che l'implementazione Sun utilizza AtomicLong quindi immagino che sia thread-safe (come notato anche da Peter Lawrey (+1)).

EDIT2 : OpenJDK utilizza anche AtomicLong per il seme. Come altri hanno già detto, non è ancora bene fare affidamento su questo.


3

Ecco come ho affrontato il problema senza dare per scontato che Random utilizzi variabili atomiche. Può ancora entrare in collisione in modo casuale se currentTime * thread idè uguale in futuro, ma è abbastanza raro per le mie esigenze. Per evitare veramente la possibilità di collisioni, potresti fare in modo che ogni richiesta attenda un timestamp di orologio univoco.

/**
 * 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());
    }
};

Su! D: è una (24*60*60*1000)parte significativa?
Jin Kwon

1
Sì, era una soluzione sporca. Il (24*60*60*1000)era così che un filo con ID 12a xxxxxxxxxx045millis non ha ottenuto seminato lo stesso di un filo 22a xxxxxxxxxx035millis. Tuttavia, non ho alcuna buona ragione per presumere che gli ID thread siano incrementali e non ci sono buoni motivi per pensare che domani crei thread in momenti più casuali rispetto a oggi. Ho semplificato l'alg ora e aggiornato la descrizione per identificare il difetto.
Ryan

0

La Randomclasse non è configurata per l'utilizzo di un'istanza in più thread. Naturalmente, se lo facessi, probabilmente aumenterai la possibilità di diventare imprevedibile e più vicino a numeri casuali . Ma dal momento che è un generatore pseudo-casuale, non riesco a capire perché dovresti condividere un'istanza. C'è un requisito più specifico?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.