Cet article étudie principalement le contenu lié aux problèmes ABA et à l'évitement en Java, comme suit.
Dans le chapitre 15 du livre "Java Concurrency Practical Practice Practice", il y a une pile de concurrence implémentée en utilisant des variables atomiques, et le code est le suivant:
Node de classe publique {élément de chaîne finale publique; Node public Suivant; Node public (élément de chaîne) {this.item = item;}} classe publique concurrentStack {atomicreference <Node> top = new atomiCreference <Node> (); public void push (string item) {node newtop = new node (item); node oldtop; do {oldtop = top.get (); newtop.next = oldtop;} while (! top .....copparendset (oldtop, newtop);} public pop () {node newtop; node oldtop; do {oldtop = top.get (); if (oldtop == null) {return null;} newtop = oldtop.next;} while (! top.comPareAndset (oldtop, newtop)); return oldtop.item;}}}Cet exemple ne causera pas de problèmes ABA. Quant à savoir pourquoi ce n'est pas le cas, je l'expliquerai plus tard. Parlons d'abord des problèmes ABA.
Qu'est-ce que ABA?
Citez le livre original: Si les nœuds de l'algorithme peuvent être utilisés cycliquement, ce problème peut se produire lors de l'utilisation de l'instruction "Comparer et échanger". Dans l'opération CAS, il sera jugé que "la valeur de V est-elle toujours un?", Et si oui, l'opération de mise à jour se poursuivra. Dans certains algorithmes, si la valeur de V passe d'abord de A à B puis de B à A, alors CAS fonctionnera avec succès.
Exemples d'ABA
Parfois, les conséquences causées par l'ABA sont très graves. Modifions l'exemple de la pile de concurrence pour voir quels problèmes aba causera:
Node de classe publique {élément de chaîne finale publique; Node public Suivant; Node public (élément de chaîne) {this.item = item;}} classe publique concurrentStack {atomicreference <Node> top = new atomiCreference <Node> (); public void push (node node) {node oldtop; do {oldtop = top.get (); node.next = oldtop;} while (! top ..comPareAndset (oldtop, node);} public node pop (int time) {Node newtop; oldtop; do {oldtop = top.get (); if (oldtop == null) {return null;} newtop = oldtop.next; timeunit.seconds.sleep (time);} while (! top ......copparingFaites attention aux modifications ici, Node n'a pas changé
Concentrez-vous sur les changements dans le stack concurrent
1. Méthode push: à l'origine, en utilisant du contenu pour construire le nœud, mais maintenant passer directement dans le nœud, qui répond à l'exigence de "nœuds dans l'algorithme peut être recyclé"
2. Le sommeil de la méthode POP, qui simule l'exécution du fil afin d'observer les résultats.
Appuyons d'abord deux nœuds dans la pile:
ConcurrentStack stack = new concurrentStack (); stack.push (nouveau nœud ("a")); stack.push (nouveau nœud ("b"));Créez ensuite deux threads pour effectuer des opérations entrant et sortant de la pile
Le thread a d'abord exécute l'empilement: laissez Nodea sortir de la pile
stack.pop (3);
Pour une raison quelconque, le thread A a été exécuté depuis longtemps et a utilisé 3 secondes
Le thread B exécute la pile puis pénètre dans la pile: d'abord, Nodea et NodeB sont libérés, puis laissez NODEC, NODEC et NODEA être entré (Nodea est en haut de la pile)
Nœud a = stack.pop (0); stack.pop (0); stack.push (nouveau nœud ("d")); stack.push (nouveau nœud ("c")); stack.push (a);Remarque: le fil B implémente le recyclage des nœuds. Il libère d'abord tous les contenus de la pile, puis les met dans la pile. Enfin, le contenu en haut de la pile est le nœud qui a été publié auparavant.
Une fois que le thread B a effectué ces actions, le thread A exécutera CAS. Pour le moment, CAS peut exécuter avec succès.
Selon l'idée d'origine, après l'exécution des threads A et B, le contenu de la pile doit être: C et D, C est en haut de la pile, mais le résultat de l'exécution ici est qu'il n'y a rien dans la pile, qui est le problème ABA.
Comment éviter les problèmes ABA
AtomicstampeDrediference et atomicmarkablereference sont fournis en Java pour résoudre les problèmes ABA
ATOMICSTAMPEDREDERFEFER peut mettre à jour atomiquement deux valeurs: référence et numéro de version, et distinguer l'utilisation du cycle du nœud par numéro de version. Voyons l'exemple d'atomicstampeDeDreference:
classe publique concurrentStack {atomicstampeDreference <Node> top = new atomicstampeDeReference <Node> (null, 0); public void push (node node) {node oldtop; int v; do {v = top.getStamp (); oldtop = top.getReference (); Node.next = oldtop;} while (! Node, v, v + 1)); //} while (! top ...... null;} newtop = oldtop.next; try {timeunit.seconds.sleep (time);} catch (interruptedException e) {e.printStackTrace ();}} while (! top ..ComaSedset (oldtop, newtop, v, v + 1)); //} while (! Top.CompaEndset (oldtop, newtop, top.getStamp (), top.getStamp ())); return oldtop;} public void get () {node node = top.getReference (); while (node! = null) {System.out.println (node.getItem ()); node = node.getNode ();}}}Remarque: vous ne pouvez pas utiliser la méthode de commentaire, sinon il ne sera pas différent de simplement utiliser des variables atomiques.
AtomicMarkableReference peut mettre à jour atomiquement un marqueur de type booléen et des types de référence, voir l'exemple suivant:
AtomicmarkableReference <Node> top = new atomicmarkableRereference <Node> (null, true); public void push (nœud nœud) {node oldtop; booléen v; do {v = top.ismarked (); oldtop = top.getReference (); node.next = oldtop;} while.Résumer
Ce qui précède est tout le contenu de cet article sur une brève discussion sur les problèmes et l'évitement de l'ABA en Java. J'espère que ce sera utile à tout le monde. Les amis intéressés peuvent continuer à se référer à d'autres sujets connexes sur ce site. S'il y a des lacunes, veuillez laisser un message pour le signaler. Merci vos amis pour votre soutien pour ce site!