È valido condividere un'istanza della Random
classe tra più thread? E nextInt(int)
in particolare per chiamare da più thread?
java.util.concurrent.ThreadLocalRandom
.
È valido condividere un'istanza della Random
classe tra più thread? E nextInt(int)
in particolare per chiamare da più thread?
java.util.concurrent.ThreadLocalRandom
.
Risposte:
È 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.
È thread-safe, anche se non lo è stato sempre.
Vedi http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070 per maggiori dettagli.
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.
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. AtomicLong
viene utilizzato per la sicurezza del thread sulla generazione del seme.
Come detto, è un thread save, ma potrebbe essere saggio usarlo java.util.concurrent.ThreadLocalRandom
secondo 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
ejava.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.
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.
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());
}
};
(24*60*60*1000)
parte significativa?
(24*60*60*1000)
era così che un filo con ID 12
a xxxxxxxxxx045
millis non ha ottenuto seminato lo stesso di un filo 22
a xxxxxxxxxx035
millis. 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.
La Random
classe 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?