Este artigo estuda principalmente o conteúdo relacionado sobre problemas de ABA e prevenção em Java, como segue.
No capítulo 15 do livro "Java Concurrency Practical Practice", existe uma pilha de simultaneidade implementada usando variáveis atômicas, e o código é o seguinte:
public class Node {public final string item; public node a seguir; public node (string item) {this.item = item;}} classe pública ConcurrentStack {AtomicReference <Node> top = new AtomicReference <Node> (); public void push (string item) {node newtop = new node (item); node antigop; do {Oldtop = top.get (); newtop.next = Oldtop;} while (! newtop; node Oldtop; do {Oldtop = top.get (); if (Oldtop == null) {return null;} newtop = oldtop.next;} while (! top.compareandsset (Oldtop, newtop)); retorna Oldtop.Item;}}}}}}}}Este exemplo não causará problemas de ABA. Quanto ao motivo de não ser, explicarei mais tarde. Vamos falar sobre os problemas da ABA primeiro.
O que é ABA?
Cite o livro original: se os nós no algoritmo puderem ser usados ciclicamente, esse problema poderá ocorrer ao usar a instrução "compare e troca". Na operação do CAS, será julgado que "o valor de V ainda é A?" E, em caso afirmativo, a operação de atualização continuará. Em alguns algoritmos, se o valor de v mudar primeiro de A para B e depois de B a A, o CAS funcionará com sucesso.
Exemplos de ABA
Às vezes, as consequências causadas pelo ABA são muito graves. Vamos modificar o exemplo da pilha de simultaneidade para ver quais problemas a ABA causará:
public class Node {public final string item; public node a seguir; public node (string item) {this.item = item;}} classe pública ConcurrentStack {AtomicReference <Node> top = new AtomicReference <Node> (); public void push (nó nó) {node Oldtop; do {Oldtop = top.get (); node.next = Oldtop;} while (! top.comparandSet (Oldtop, node); Oldtop; do {Oldtop = top.get (); if (Oldtop == null) {return null;} newtop = Oldtop.Next; TimeUnit.Seconds.Sleep (tempo);} while (!Preste atenção às mudanças aqui, o nó basicamente não mudou
Concentre -se nas mudanças no concorrente
1. Método push: Originalmente, usando o conteúdo para construir o nó, mas agora passa diretamente no nó, que atende ao requisito de "nós no algoritmo podem ser reciclados"
2. O sono do método pop, que simula a execução do encadeamento para observar os resultados.
Vamos primeiro pressionar dois nós na pilha:
ConcurrentStack Stack = new ConcurrentStack (); Stack.push (novo nó ("A")); Stack.push (novo nó ("b"));Em seguida, crie dois tópicos para executar operações entrando e saindo da pilha
Principado primeiro executa o empilhamento: deixe nodea sair da pilha
Stack.pop (3);
Por algum motivo, o thread A foi executado há muito tempo e usou 3 segundos
O thread B executa a pilha e depois entra na pilha: primeiro, nodea e nodeb são liberados e depois deixados com a cabeça, nodec e nodea serem inseridos (Nodea está no topo da pilha)
Nó a = pilha.pop (0); Stack.pop (0); Stack.push (novo nó ("D")); Stack.push (novo nó ("c")); Stack.push (a);NOTA: O encadeamento B implementa a reciclagem de nós. Primeiro, ele libera todo o conteúdo da pilha e depois os coloca na pilha. Finalmente, o conteúdo na parte superior da pilha é o nó que foi lançado antes.
Depois que o Thread B executou essas ações, o Thread A executará CAS. Neste momento, o CAS pode executar com sucesso.
De acordo com a idéia original, após a execução dos threads A e B, o conteúdo da pilha deve ser: C e D, C está na parte superior da pilha, mas o resultado da execução aqui é que não há nada na pilha, que é o problema da ABA.
Como evitar problemas de ABA
AtomicstampedReference e AtomicmarkableReference são fornecidos em Java para resolver problemas ABA
AtomicstampedReference pode atualizar atomicamente dois valores: referência e número da versão e distinguir o uso do ciclo do nó pelo número da versão. Vamos ver o exemplo da atomicstampedReference:
classe pública ConcurrentStack {AtomicstampedReference <Node> top = new AtomicstampedReference <Node> (null, 0); public void push (nó nó) {node Oldtop; int v; do {v = top.getstamp (); Oldtop = top.Gereference (); node.next = OldTop; nó, v, v+1)); //} while (! top.compareandset (Oldtop, nó, top.getstamp (), top.getStamp ()+1));} public node pop (int time) {node newtop; node antigo; int v; do {v = top.getstamp (); null;} newtop = Oldtop.Next; tente {timeUnit.Seconds.sleep (tempo);} catch (interruptEdException e) {e.printStacktrace ();}} while (! top.compareandSet (Oldtop, newtop, v, v+1); newtop, top.getstamp (), top.getstamp ())); retornar Oldtop;} public void get () {node node = top.getReference (); while (node! = null) {System.out.println (node.getItem ()); node = node.getNode ();}}}Nota: Você não pode usar o método de comentário, caso contrário, ele não será diferente de simplesmente usar variáveis atômicas.
AtomicmarkableReference pode atualizar atomicamente um marcador de tipo booleano e tipos de referência, consulte o exemplo a seguir:
AtomicmarkableReference <Node> top = new AtomicmarkableReference <Node> (nulo, true); public void push (nó nó) {node Oldtop; boolean v; do {v = top.ismoked (); oldtop = top.getReference (node.next = Oldtop;Resumir
O exposto acima é todo o conteúdo deste artigo sobre uma breve discussão sobre problemas da ABA e evitação em Java. Espero que seja útil para todos. Amigos interessados podem continuar se referindo a outros tópicos relacionados neste site. Se houver alguma falha, deixe uma mensagem para apontá -la. Obrigado amigos pelo seu apoio para este site!