Maison > Java > javaDidacticiel > Une introduction aux méthodes et principes de l'implémentation java.util.Random

Une introduction aux méthodes et principes de l'implémentation java.util.Random

巴扎黑
Libérer: 2017-09-08 09:50:31
original
3367 Les gens l'ont consulté

La classe java.util.Random dans la bibliothèque de classes utilitaires Java fournit des méthodes pour générer différents types de nombres aléatoires. L'article suivant présente principalement des informations pertinentes sur le principe d'implémentation de java.util.Random. beaucoup de détails, les amis dans le besoin peuvent s'y référer.

Vue d'ensemble

java.util.Random peut générer des nombres aléatoires de types int, long, float, double et goussien. C'est également la plus grande différence entre cette méthode et la méthode Random() de java.lang.Math, qui génère uniquement des nombres aléatoires de type double.

Les instances de cette classe sont utilisées pour générer un flux de nombres pseudo-aléatoires. Cette classe utilise une graine de 48 bits modifiée par une formule congruente linéaire. Si deux instances de Random sont créées avec la même graine, elles généreront et renverront la même séquence de nombres en complétant la même séquence d'appels de méthode sur chaque instance.

Exemple


public class RandomTest {
 public static void main(String[] args) {
 testRandom();
 System.out.println("---------------------");
 testRandom();
 System.out.println("---------------------");
 testRandom();
 }
 
 public static void testRandom(){
 Random random = new Random(1);
 for(int i=0; i<5; i++){
  System.out.print(random.nextInt()+"\t");
 }
 System.out.println("");
 }
}
Copier après la connexion

Résultat de sortie :


D'après les résultats, nous avons constaté que tant que les graines sont les mêmes, la séquence de nombres aléatoires obtenue est cohérente. Il s’agit d’une implémentation de nombres pseudo-aléatoires, et non de vrais nombres aléatoires.

Analyse aléatoire du code source

Structure de classe aléatoire


class Random implements java.io.Serializable {
 private final AtomicLong seed;

 private static final long multiplier = 0x5DEECE66DL;
 private static final long addend = 0xBL;
 private static final long mask = (1L << 48) - 1;
 private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);
Copier après la connexion

Là sont des références La méthode de construction


public Random(long seed) {
 if (getClass() == Random.class)
  this.seed = new AtomicLong(initialScramble(seed));
 else {
  // subclass might have overriden setSeed
  this.seed = new AtomicLong();
  setSeed(seed);
 }
}

private static long initialScramble(long seed) {
 return (seed ^ multiplier) & mask;
}
Copier après la connexion

génère des nombres aléatoires en passant une graine À partir de l'exemple ci-dessus, on constate que la séquence de nombres aléatoires est générée par la même graine. est le même s'il est utilisé à chaque fois. Si vous souhaitez générer des séquences différentes, vous ne pouvez transmettre qu'une graine différente à chaque fois.

Méthode de construction sans paramètre


public Random() {
 this(seedUniquifier() ^ System.nanoTime());
 }
private static long seedUniquifier() {
 // L&#39;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;
 }
}
Copier après la connexion

Découvert grâce au code source, le paramètre- moins de méthode de construction, il génère automatiquement une graine pour nous et utilise la méthode de spin CAS pour s'assurer que la graine obtenue est différente à chaque fois, garantissant ainsi que la séquence aléatoire obtenue à chaque fois new Random() est incohérente.

Méthode nextInt() : Obtenez un nombre aléatoire int


public int nextInt() {
 return next(32);
}

protected int next(int bits) {
 long oldseed, nextseed;
 AtomicLong seed = this.seed;
 do {
  oldseed = seed.get();
  nextseed = (oldseed * multiplier + addend) & mask;
 } while (!seed.compareAndSet(oldseed, nextseed));
 return (int)(nextseed >>> (48 - bits));
}
Copier après la connexion

À partir du code que nous pouvons On constate que tant que la graine est déterminée, le nombre généré à chaque fois est généré à l'aide d'un algorithme fixe, donc tant que la graine est déterminée, la séquence générée à chaque fois est fixe.

Chaque fois que la graine est mise à jour, CAS est utilisé pour la mettre à jour. Dans un environnement à haute concurrence, les performances sont un problème.

Problèmes de sécurité

Imaginez s'il s'agit d'une plateforme de loterie, tant que la graine est déterminée, la séquence générée sera la même à chaque temps . De cette manière, cette faille peut être utilisée pour prédire les numéros du prochain tirage de loterie, ce qui peut facilement être exploité par certaines personnes.

jdk vous recommande d'essayer d'utiliser SecureRandom pour générer des nombres aléatoires.

SecureRandom

SecureRandom est un puissant générateur de nombres aléatoires. Les principaux scénarios d'application sont : des numéros de données à des fins de sécurité, tels que la génération de secrets. clé ou identifiant de session. Dans l'article ci-dessus "Sécurité des nombres pseudo-aléatoires", les problèmes de sécurité des générateurs de nombres aléatoires faibles vous ont été révélés, et l'utilisation de générateurs de nombres aléatoires puissants comme SecureRandom réduira considérablement le risque de choses. ça va mal.

Pour générer des nombres aléatoires à haute résistance, il existe deux facteurs importants : la graine et l'algorithme. Il peut y avoir de nombreux algorithmes et le choix de la graine est généralement un facteur très critique. Par exemple, Random, sa graine est System.currentTimeMillis(), donc ses nombres aléatoires sont des nombres pseudo-aléatoires prévisibles et faibles.
L'idée de générer des nombres pseudo-aléatoires forts : collecter diverses informations sur l'ordinateur, le temps de saisie au clavier, l'état d'utilisation de la mémoire, l'espace libre du disque dur, le délai d'E/S, le nombre de processus, le nombre de threads et d'autres informations, l'horloge du processeur, pour obtenir un nombre approximativement aléatoire, les graines atteignent principalement l'imprévisibilité.

Pour faire simple, utilisez un algorithme de cryptage pour générer une graine aléatoire très longue, afin que vous ne puissiez pas deviner la graine, et donc ne pas déduire le numéro de séquence aléatoire.

Problèmes de performances aléatoires

À partir du code source aléatoire, nous avons découvert que CAS est utilisé pour mettre à jour la graine chaque fois qu'un nombre aléatoire est obtenu. valeur. De cette manière, il y aura un grand nombre de tentatives CAS dans un environnement à forte concurrence, ce qui entraînera une dégradation des performances. À l’heure actuelle, il est recommandé d’utiliser la classe ThreadLocalRandom pour générer des nombres aléatoires.

Principe d'implémentation de ThreadLocalRandom

Classe Thread

Il existe une propriété threadLocalRandomSeed dans la classe Thread.

Structure ThreadLocalRandom

La variable SEED est le décalage de threadLocalRandomSeed dans l'objet Thread.

Méthode ThreadLocalRandom.nextSeed()

À partir de cette méthode, nous constatons que la valeur de départ de chaque thread est stockée dans In la propriété threadLocalRandomSeed de l'objet Thread.

Conclusion

Étant donné que les graines de ThreadLocalRandom sont stockées dans des objets Thread, CAS ne sera pas utilisé pour garantir une concurrence élevée lors de l'acquisition d'objets Random. Les valeurs obtenues à chaque fois sont incohérentes.
Chaque thread conserve sa propre graine. Lorsque chaque thread doit obtenir des nombres aléatoires, il obtient la graine du thread actuel à partir de l'objet Thread actuel et obtient des nombres aléatoires. Les performances sont grandement améliorées.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal