Antes de ler este artigo, você pode primeiro ler " Introdução e uso do pacote atômico Java Multithread " para aprender sobre o conteúdo relevante do pacote atômico.
1. O que é atômico?
A palavra atômica tem algo a ver com átomos, que já foi considerado a unidade da menor questão. Atomic em um computador significa que ele não pode ser dividido em várias partes. Se um pedaço de código for considerado atômico, significa que o código não pode ser interrompido durante a execução. De um modo geral, as instruções atômicas são fornecidas pelo hardware e são fornecidas pelo software para implementar métodos atômicos (um encadeamento não será interrompido após a entrada do método até que sua execução seja concluída)
Na plataforma X86, a CPU fornece os meios para travar o barramento durante a execução de instruções. Há um líder #hlockpin no chip da CPU. Se o prefixo "bloqueio" for adicionado a uma instrução no programa de linguagem de montagem, o código da máquina de montagem fará com que a CPU diminua o potencial do #HlockPin ao executar esta instrução e a liberar até o final desta instrução, travando assim o barramento. Dessa forma, outras CPUs no mesmo barramento não podem acessar a memória através do barramento por enquanto, garantindo a atomicidade desta instrução em um ambiente multiprocessador.
2. Variáveis atômicas em java.util.concurrent
Seja direto ou indireto, quase todas as classes no pacote java.util.Concurrent usam variáveis atômicas, não sincronização. Classes como o ConcurrentLinkedQueue também usam variáveis atômicas para implementar diretamente o algoritmo sem espera, enquanto classes como o concurso de uso do Reentrantlock para bloquear quando necessário. O ReentrantLock usa variáveis atômicas para manter a fila de rosca aguardando o bloqueio.
Sem as melhorias da JVM no JDK5.0, essas classes não serão construídas, que expõem (à biblioteca de classes, não à classe de usuário) interfaces para acessar as primitivas de sincronização no nível de hardware. As classes variáveis atômicas e outras classes em java.util.Concurrent expõem essas funções à classe de usuário
classe atômica de java.util.concurrent.atomic
Este pacote fornece um conjunto de classes atômicas. Seu recurso básico é que, em um ambiente multithread, quando vários threads executam métodos contidos em casos dessas classes ao mesmo tempo, é exclusivo, ou seja, quando um encadeamento entra no método e executa as instruções nele, não será interrompido por outros roscas e outros roscas são como bloqueios de rotação. Até que o método seja executado, a JVM selecionará outro thread da fila que espera para entrar. Este é apenas um entendimento lógico. De fato, é implementado com a ajuda de instruções relevantes de hardware e não bloqueará threads (ou está bloqueado no nível do hardware). As classes podem ser divididas em 4 grupos
Atomicbooliano, atomicinteger, atomiclong, atomicreferência
AtomicintegerRay, atomiclonGray
AtomiclongfieldUpdater, atomicintegerfieldUpdater, atomicReferenceFieldUpDater
AtomicmarkableReference, atomicstampedReference, atomicReferencearray
Entre eles, atomicbooliano, atomicinteger, atomiclong e atomicreferência são semelhantes.
Primeiro de tudo, atomicbooliano, atomicinteger, atomiclong e atomicreference APIs são semelhantes: tome um exemplo de atomicreferência
Crie uma pilha segura para threads com atomicreferência
classe pública LinkedStack <T> {private AtomicReference <nó <T>> Stacks = new AtomicReference <nó <T>> (); public t push (t e) {node <t> OldNode, newNode; enquanto (true) {// o processamento aqui é muito especial e deve ser o caso. OldNode = Stacks.get (); newNode = new Node <T> (e, OldNode); if (Stacks.compareandset (OldNode, newNode)) {return e;}}} public t POP () {node <T> OldNode, newNode; while (antigo) {OldNode = Stacks. (); (Stacks.comparenderndset (OldNode, newNode)) {return OldNode.Object;}}} Nó da classe final estática privada <t> {objeto T privado; nó privado <T> próximo; nó privado (objeto t, nó <T> a seguir) {this.Object = Object; this.next = a seguir;Em seguida, concentre -se na atualização atômica do campo.
AtomicIntegerFieldUpDater <T>/AtomiclongfieldUpdater <t>/atomicReferencefieldUpDater <t, v> é o valor de um campo com base na reflexão.
A API correspondente também é muito simples, mas também possui algumas restrições.
(1) O campo deve ser do tipo volátil! O que é volátil? Verifique " Explicação detalhada de palavras -chave voláteis em Java "
(2) O tipo de descrição do campo (Modificador público/protegido/padrão/privado) é consistente com a relação entre o chamador e o campo de objeto de operação. Ou seja, o chamador pode operar diretamente o campo de objeto e, em seguida, refletir e executar operações atômicas. No entanto, para os campos da classe pai, a subclasse não pode ser operada diretamente, embora a subclasse possa acessar os campos da classe pai.
(3) Pode ser apenas uma variável de instância, não uma variável de classe, ou seja, não pode adicionar palavras -chave estáticas.
(4) Ele só pode ser variável modificado e não pode ser transformado em variáveis finais, porque a semântica da final não é modificada. De fato, a semântica do conflito final e volátil e essas duas palavras -chave não podem existir ao mesmo tempo.
(5) Para atomicintegerfieldUpdater e AtomiclongfieldUpdater, eles só podem modificar campos de tipo int/longo e não podem modificar seu tipo de invólucro (número inteiro/longo). Se você deseja modificar o tipo de embalagem, precisará usar o AtomicReferenceFieldUpDater.
O método de operação é descrito no exemplo a seguir.
importar java.util.Concurrent.atomic.atomicintegerfieldUpdater; public class AtomicintegerfieldupDaterDemo {classe demodata {public volátil int valor1 = 1; volátil Int Value2 = 2; protegido volátil int valor3 = 3; private volátil Int Value4 = 4; {return atomicintegerfieldupdater.newupdater (demodata.class, fieldname);} void doit () {Demodata data = new Demodata (); system.out.println ("1 ==>"+getUpDater ("value1"). "+getUpDater (" value2 "). {AtomicIntegerfieldUpdaterDemo Demo = new AtomicIntegerFieldUpDaterDemo (); Demo.doit ();}}No exemplo acima, o valor de campo3/valor4 de demodata não é visível para a classe AtomicIntegerfieldupDaterDemo, portanto seu valor não pode ser diretamente modificado através da reflexão.
Um par de <objeto, booleano> descrito pela classe AtomicMarkableReference pode modificar atomicamente o valor do objeto ou booleano. Essa estrutura de dados é mais útil em algumas descrições de cache ou estado. Essa estrutura pode melhorar efetivamente a taxa de transferência ao modificar o objeto/booleano individualmente ou simultaneamente.
A classe AtomicstampedReference mantém referências de objeto com "sinalizadores" inteiros e pode ser atualizado atomicamente. Comparado com o <objeto, booleano> da classe AtomicmarkableReference, o atomicstampedReference mantém uma estrutura de dados semelhante a <objeto, int>, que é na verdade uma contagem simultânea de objetos (referências). Mas, diferentemente do AtomicInteger, essa estrutura de dados pode transportar uma referência de objeto e pode executar operações atômicas nesse objeto e contar ao mesmo tempo.
"Problema ABA" será mencionado no final deste artigo, e atomicmarkableReference/AtomicstampedReference é útil na solução de "Problema ABA".
Iii. O papel do atômico
Isso permite que a operação de dados únicos seja atomizada
Construir código complexo e sem bloqueio usando classes atômicas
O acesso a 2 ou mais variáveis atômicas (ou executando 2 ou mais operações em uma única variável atômica) é geralmente considerada para exigir sincronização para que essas operações possam ser usadas como uma unidade atômica.
Sem algoritmo de travamento e sem espera
Os algoritmos de simultaneidade baseados no CAS (comparaandswap) são chamados de algoritmos sem trava, porque os threads não precisam mais esperar pelo bloqueio (às vezes chamado de mutexes ou peças críticas, dependendo da terminologia da plataforma de threads). Se a operação do CAS é bem -sucedida ou falha, em ambos os casos, é concluída em um tempo previsível. Se o CAS falhar, o chamador poderá tentar novamente a operação do CAS ou tomar outras operações adequadas.
Se cada thread continuar operando quando outros threads estiverem atrasados (ou até falharem), pode-se dizer que o algoritmo está livre de espera. Por outro lado, o algoritmo livre de bloqueio exige que apenas um determinado thread sempre execute a operação. (Outra definição de não espera é garantir que cada fio calcule corretamente suas próprias operações em suas etapas limitadas, independentemente das operações, tempo, crossover ou velocidade de outros threads. Esse limite pode ser uma função do número de encadeamentos na operação do sistema; por exemplo, se houver que o pior dos roscos seja o pior dos threads.
Nos últimos 15 anos, as pessoas realizaram extensas pesquisas sobre algoritmos sem espera e sem bloqueio (também conhecidos como algoritmos não bloqueadores), e muitas pessoas descobriram algoritmos não bloqueadores em estruturas de dados gerais. Os algoritmos não bloqueadores são amplamente utilizados no sistema operacional e no nível da JVM, executando tarefas como encadeamento e agendamento de processos. Embora sua implementação seja mais complexa, eles têm muitas vantagens sobre algoritmos alternativos baseados em trava: eles podem evitar perigos como inversão prioritária e impasse, a concorrência é mais barata, a coordenação ocorre em um nível de granularidade mais fino, permitindo um maior grau de paralelismo e assim por diante.
Comum:
Contador não bloqueador
Pilha não bloqueadora ConcurrentStack
Lista vinculada não bloqueada ConcurrentLinkedQueue
Perguntas da ABA:
Porque antes de alterar o V, o CAS pergunta principalmente "se o valor de V ainda é A", antes de ler V pela primeira vez e executar operações do CAS em V, alterando o valor de A para B e depois voltar para A confundirá o algoritmo baseado no CAS. Nesse caso, a operação do CAS terá sucesso, mas em alguns casos o resultado pode não ser o que você esperava. Esse tipo de problema é chamado de problema ABA, que geralmente é tratado associando uma tag ou número de versão a cada valor a ser executado na operação do CAS e atualizando atomicamente os valores e tags. A classe AtomicstampedReference suporta esse método.
Resumir
O exposto acima é toda a explicação detalhada deste artigo sobre o operador de variáveis atômicas e classes atômicas no pacote atômico multiereado Java. Espero que seja útil para todos. Amigos interessados podem continuar se referindo a este site:
Programação Java: Deadlock multi-thread e comunicação entre threads são um código simples
Programação multiereada Java pequeno exemplo simula o sistema de estacionamento
Uma breve discussão sobre as vantagens e exemplos de código do Java Multithreading
Se houver alguma falha, deixe uma mensagem para apontá -la.