La mia vera domanda è se l'opzione 1 è matematicamente valida.
Iniziamo con opzione 2. Il generatore di numeri casuali utilizzato da java.util.Random
è specificato nella javadoc come segue:
La classe utilizza un seme 48 bit, che viene modificato utilizzando una formula lineare congruenziale . (Vedere Donald Knuth, L'arte della Programmazione del computer, Volume 2, Sezione 3.2.1.)
e vi sono dettagli più specifici nei vari metodi 'javadocs.
Ma il punto è che stiamo usando una sequenza generata da una formula congruenziale lineare, e tali formule hanno un grado significativo di auto-correlazione ... che potrebbe essere problematico.
Ora con l'opzione 1, si utilizza un'altra istanza Random
con un nuovo seme ogni volta e si applica un round della formula LC. Quindi stai ricevendo una sequenza di numeri che potrebbero essere autocorrelati con i semi. Tuttavia, i semi vengono generati in modi diversi, a seconda della versione di Java.
Java 6 fa questo:
public Random() { this(++seedUniquifier + System.nanoTime()); }
private static volatile long seedUniquifier = 8682522807148012L;
... che non è molto casuale a tutti. Se hai creato istanze Random
a intervalli costanti, è probabile che i semi siano ravvicinati, e quindi la sequenza di numeri casuali prodotta dalla tua opzione # 1 può essere auto-correlata.
Al contrario, Java 7 e 8 fanno questo:
public Random() {
this(seedUniquifier()^System.nanoTime());
}
private static long seedUniquifier() {
// L'Ecuyer, "Tables of Linear Congruential Generators of
// Different Sizes and Good Lattice Structure", 1999
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
private static final AtomicLong seedUniquifier
= new AtomicLong(8682522807148012L);
La sequenza dei semi prodotti dalla cui sopra sono probabilmente un'approssimazione molto meglio (vero) casualità. Questo probabilmente rende l'opzione n. 1 superiore all'opzione n. 2.
Lo svantaggio dell'opzione n. 1 in Java da 6 a 8 è che la chiamata di System.nanoTime()
probabilmente implica una chiamata di sistema. Questo è relativamente costoso.
Quindi la risposta breve è che è Java versione specifica quale di opzione # 1 e # 2 opzione produce una migliore qualità dei numeri "casuali" ... dal punto di vista matematico.
In entrambi i casi, la distribuzione dei numeri sarà uniforme su una dimensione di campione abbastanza grande, anche se non sono sicuro che sia significativo parlare di distribuzioni di probabilità quando il processo è deterministico.
Tuttavia, nessuno dei due metodi sarebbe adatto come generatore di numeri casuali di "forza crittografica".
andare con l'opzione 3: 'ThreadLocalRandom.current(). NextInt()'. Inoltre, ti stai sbagliando a proposito dei rand allo stesso tempo, http://stackoverflow.com/a/20060801/995891 non solo utilizza il tempo per inizializzare. – zapl
Grazie non ne ero consapevole. Aggiornerò la domanda –