JAVA multithreading, algo que os entrevistadores gostam de perguntar
Algumas coisas conceituais
Atomicidade significa que a operação é indivisível. Independentemente de ser multi-core ou single-core, uma quantidade atômica, apenas um thread pode operar nela por vez. Resumindo, as operações que não são interrompidas pelo planejador de thread durante toda a operação podem ser consideradas atômicas. Por exemplo, a = 1;
Não atomicidade: isso significa que o escalonador de thread interromperá a operação durante todo o processo. Operações
como "a ++" não são atômicas, pois podem ter que passar pelas duas etapas a seguir:(1) Pegue o valor de um
(2) Calcule a + 1
Se houver dois threads t1, t2 está executando tais operações. Após a primeira etapa, t1 foi interrompido pelo escalonador de thread antes que tivesse tempo de adicionar 1, então t2 começou a executar. Depois que t2 foi executado, t1 começou a executar a segunda etapa (neste momento, o valor de a em t1 pode ainda seja o valor antigo, não é certo, ele só aparecerá se o valor de a na thread t2 não for atualizado para t1 no tempo). Ocorreu um erro neste momento, e a operação de t2 é equivalente a ser ignorada
Agendamento de thread JAVA - agendamento preemptivo (prioridade)
CAS— (compare e troque) compare e troque
Adote o pensamento de bloqueio otimista - sempre pense que você pode concluir a operação
Quando vários encadeamentos manipulam uma variável, apenas um encadeamento será atualizado com sucesso, os outros falham e o encadeamento com falha pode tentar novamente
Rotação CAS esperando
Bloqueia ou
synchronized
pode ser alcançado operação atômica de palavra-chave, então por que usar CAS, porque o bloqueio ou desempenho de palavra-chave sincronizada trouxe grande perda, mas com o bloqueio otimista de CAS pode ser alcançado, é na verdade o uso direto das instruções de nível de CPU, então o desempenho é muito alto.Então, como o CAS realiza o bloqueio de rotação? O CAS usa instruções da CPU para garantir a atomicidade da operação para obter o efeito de bloqueio. Quanto ao spin, geralmente é realizado com um loop infinito. Desse modo, em um loop infinito, é executada uma operação CAS. Quando a operação é bem-sucedida e retorna verdadeiro, o loop termina; quando retorna falso, o loop continua e a operação CAS continua a ser tentada até retornar verdadeiro.
Insira o código-fonte do CAS para ver
import java.util.concurrent.atomic.AtomicInteger;
Defina atomicamente o valor para o valor atualizado fornecido ( update
), se o valor atual for igual ao valor esperado ( expect
). Retorna verdadeiro, atualiza o valor da variável, o valor real não é igual ao valor esperado, retorna falso, a thread não faz nada, CAS retorna o valor da variável atual;
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
Dentro unsafe.compareAndSwapInt(this, valueOffset, expect, update);
dele está um native
método, usando a implementação c ++, se estiver interessado pode ir e ver os arquivos de código-fonte JDK safe.cpp, o CAS opera diretamente com o sistema operacional;
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
Problema ABA causado por CAS
O que é ABA?
Posso saber do exposto que existe uma premissa importante para a implementação do algoritmo CAS: você precisa retirar os dados em um determinado momento da memória, e depois comparar e substituí-los no momento seguinte. Nesta diferença de tempo , os dados podem ter mudado, o que leva ao problema ABA;
Solução: parte do problema é resolvido adicionando o número da versão (versão),
AQS é um sincronizador de fila abstrato
O AQS mantém um estado de variável de recurso compartilhado com semântica volátil (suportando visibilidade sob vários threads) e uma fila de espera de thread FIFO (quando o estado de competição multithread é bloqueado, ele entrará nesta fila). java.util.concurrent.locks.AbstractQueuedSynchronizer
Classe abstrata, referida como AQS
A forma como AQS compartilha recursos: exclusivos e compartilhados
AQS fornece dois modos: modo exclusivo e modo compartilhado por padrão, e a implementação correspondente do JDK tem
ReentrantLock
eReentrantReadWriteLock
Exclusivo: apenas um thread pode ser executado, a implementação JAVA específica tem ReentrantLock
Compartilhado: vários threads são executados ao mesmo tempo
AQS é implementado com base em volitale e CAS. Um estado de variável do tipo valitale é mantido em AQS para
fazer um número reentrante de bloqueios reentrantes. Bloqueio e liberação de bloqueios também são realizados em torno desta variável.