1. Algoritmo sem bloqueio
Algoritmos sem bloqueio são algoritmos simultâneos que podem gerar seus threads com segurança, não por meio de spawns de bloqueio, mas por meio de formas de atomicidade nativas de hardware de baixo nível - como comparações e trocas. Algoritmos sem bloqueio são extremamente difíceis de projetar e implementar, mas podem fornecer melhor rendimento e melhor defesa contra problemas de sobrevivência, como impasse e inversão de prioridade. Use instruções de máquina atômica de baixo nível para substituir bloqueios, como comparar e trocar (CAS).
2. Tecnologia pessimista
O bloqueio exclusivo é uma técnica pessimista que assume que o pior cenário ocorre (se o bloqueio não estiver bloqueado, outros threads destruirão o estado do objeto) e mesmo que o pior cenário não ocorra, o estado do objeto ainda estará protegido por. uma fechadura.
3. Tecnologia otimista
Monitoramento de conflito de dependência. Atualize primeiro Se ocorrer um conflito durante o monitoramento, desista da atualização e tente novamente, caso contrário, a atualização será bem-sucedida. Agora os processadores têm instruções atômicas de leitura-modificação-gravação, como comparar e trocar (CAS, compare). -e- trocar).
4. Operação CAS
CAS possui 3 operandos, o valor de memória V, o antigo valor esperado A e o novo valor a ser modificado B. Se e somente se o valor esperado A e o valor de memória V forem iguais, modifique o valor de memória V para B, caso contrário não faça nada. O padrão de uso típico do CAS é: primeiro leia A de V e calcule o novo valor B com base em A e, em seguida, use CAS para alterar atomicamente o valor em V de A para B (desde que nenhum thread altere o valor de V durante este período) valor para outro valor).
Listagem 3. Código que ilustra o comportamento (mas não o desempenho) de comparar e trocar Copie o código abaixo:
classe pública SimuladoCAS {
valor interno privado;
público sincronizado int getValue() {valor de retorno};
público sincronizado int compareAndSwap(int esperadoValue, int newValue) {
int valorantigo = valor;
if (valor == valor esperado)
valor = novoValor;
retornar valorantigo;
}
}
Listagem 4. Use comparar e trocar para implementar o código de cópia de contador. O código é o seguinte:
classe pública CasCounter {
valor simulado CAS privado;
public int getValor() {
return valor.getValue();
}
incremento interno público() {
int oldValue = valor.getValue();
while (value.compareAndSwap(oldValue, oldValue + 1)! = oldValue)
valor antigo = valor.getValue();
return valorantigo + 1;
}
}
5. Variáveis atômicas
Variáveis atômicas suportam operações de atualização atômica sem proteção de bloqueio, e a camada subjacente é implementada usando CAS. Existem 12 variáveis atômicas no total, que podem ser divididas em 4 grupos: classe escalar, classe atualizadora, classe array e classe de variável composta. As variáveis atômicas mais comumente usadas são classes escalares: AtomicInteger, AtomicLong, AtomicBoolean e AtomicReference. CAS é compatível com todos os tipos.
6. Comparação de desempenho: bloqueios e variáveis atômicas
Sob contenção de baixa a média, as variáveis atômicas podem fornecer alta escalabilidade, e o desempenho das variáveis atômicas excede o dos bloqueios sob contenção de alta intensidade, os bloqueios podem evitar a contenção de forma mais eficaz e o desempenho dos bloqueios excederá o desempenho dos atômicos; variáveis. Mas numa situação prática mais realista, o desempenho das variáveis atómicas excederá o desempenho dos bloqueios.