Este artículo estudia principalmente contenido relacionado sobre problemas de ABA y evitación en Java, de la siguiente manera.
En el Capítulo 15 del libro "Práctica práctica de concurrencia Java", hay una pila de concurrencia implementada utilizando variables atómicas, y el código es el siguiente:
Public Class Node {public Final String item; public nodo Next; public nodo (string item) {this.item = item;}} clase pública 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 (topeanddSet (oldTop, newtop);} ((nottop; {) newTop; Node OldTop; do {oldTop = top.get (); if (oldTop == null) {return null;} newTop = oldtop.next;} while (! top.compareanddset (oldtop, newtop)); return oldtop.item;}}}Este ejemplo no causará problemas de ABA. En cuanto a por qué no lo es, lo explicaré más tarde. Hablemos primero sobre los problemas de ABA.
¿Qué es ABA?
Cita el libro original: si los nodos en el algoritmo se pueden usar cíclicamente, este problema puede ocurrir cuando se usa la instrucción "Comparar e intercambiar". En la operación de CAS, se juzgará que "¿es el valor de V una?", Y de ser así, la operación de actualización continuará. En algunos algoritmos, si el valor de V primero cambia de A a B y luego de B a A, entonces CAS funcionará con éxito.
Ejemplos de ABA
A veces, las consecuencias causadas por ABA son muy graves. Modificemos el ejemplo de la pila de concurrencias para ver qué problemas causará ABA:
Public Class Node {public Final String item; public nodo Next; public nodo (string item) {this.item = item;}} public class 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;Node OldTop; do {oldTop = top.get (); if (oldTop == null) {return null;} newTop = oldTop.next; timeunit.seconds.sleep (time);} while (! top.compareandset (Oldtop, newtop)); return Oldtop;}}Prestar atención a los cambios aquí, el nodo básicamente no ha cambiado
Centrarse en los cambios en Concurrentstack
1. Método de empuje: Originalmente, el uso de contenido para construir el nodo, pero ahora pasar directamente en el nodo, que cumple con el requisito de "nodos en el algoritmo se puede reciclar"
2. El sueño del método POP, que simula la ejecución del hilo para observar los resultados.
Primero presionemos dos nodos en la pila:
Concurrentstack stack = new ConcurrentStack (); stack.push (nuevo nodo ("a")); stack.push (nuevo nodo ("b"));Luego cree dos hilos para realizar operaciones que ingresan y dejando la pila
Hush A Primero ejecuta el apilamiento: deje que Nodea salga de la pila
stack.pop (3);
Por alguna razón, el hilo A se ha ejecutado durante mucho tiempo y ha usado 3 segundos
El hilo B ejecuta la pila y luego ingresa a la pila: primero, se liberan Nodea y NodeB, y luego dejan ingresar Noded, Nodec y Nodea (Nodea está en la parte superior de la pila)
Nodo a = stack.pop (0); stack.pop (0); stack.push (nuevo nodo ("d")); stack.push (nuevo nodo ("c")); stack.push (a);Nota: El hilo B implementa el reciclaje de nodos. Primero libera todos los contenidos en la pila, y luego los coloca en la pila. Finalmente, el contenido en la parte superior de la pila es el nodo que se lanzó antes.
Después de que el hilo B ha realizado estas acciones, el hilo A ejecutará CAS. En este momento, CAS puede ejecutarse con éxito.
Según la idea original, después de la ejecución de los hilos A y B, el contenido de la pila debe ser: C y D, C está en la parte superior de la pila, pero el resultado de la ejecución aquí es que no hay nada en la pila, que es el problema de ABA.
Cómo evitar problemas de ABA
AtomicstampedReference y AtomicMarkableSerference se proporcionan en Java para resolver problemas de ABA
AtomicStampedReference puede actualizar atómicamente dos valores: número de referencia y versión, y distinguir el uso del ciclo del nodo por número de versión. Veamos el ejemplo de AtomicStampedReference:
public class ConcurrentStack {AtomicStampedReference<Node> top = new AtomicStampedReference<Node>(null,0);public void push(Node node){Node oldTop;int v;do{v=top.getStamp();oldTop = top.getReference();node.next = oldTop;}while(!top.compareAndSet(oldTop, node,v,v+1));// }while(!top.compareAndSet(oldTop, node,top.getStamp(),top.getStamp()+1));}public Node pop(int time){Node newTop;Node oldTop;int v;do{v=top.getStamp();oldTop = top.getReference();if(oldTop == null){return null;} newTop = oldtop.next; try {timeUnit.seconds.sleep (time);} catch (interruptedException e) {E.PrintStackTrace ();}} while (! top.compareanddset (Oldtop, Newtop, V, V+1); //} while (! newtop, top.getStamp (), top.getStamp ())); return oldtop;} public void get () {nodo nodo = top.getReference (); while (node! = null) {system.out.println (node.getitem ()); node = node.getNode ();}}}Nota: No puede usar el método de comentarios, de lo contrario no será diferente de simplemente usar variables atómicas.
AtomicMarkableReference puede actualizar atómicamente un marcador de tipo booleano y tipos de referencia, consulte el siguiente ejemplo:
AtomicMarkableReference <Node> top = new AtomicMarkableReference <node> (null, true); public void push (nodo nodo) {node oldTop; boolean v; do {v = top.smitked (); oldTop = top.getReference (); node.next = oldTop;} while (!Resumir
Lo anterior es todo el contenido de este artículo sobre breve discusión sobre problemas de ABA y evitación en Java. Espero que sea útil para todos. Los amigos interesados pueden continuar referiéndose a otros temas relacionados en este sitio. Si hay alguna deficiencia, deje un mensaje para señalarlo. ¡Gracias amigos por su apoyo para este sitio!