Guia da palavra-chave volátil em Java

Guia da palavra-chave volátil em Java

1. Visão geral

Neste artigo rápido, vamos nos concentrar em um conceito fundamental, mas muitas vezes mal compreendido, na linguagem Java - a palavra-chavevolatile.

Em Java, cada encadeamento possui um espaço de memória separado conhecido como memória de trabalho; isso mantém os valores de diferentes variáveis ​​usadas para executar operações. Após executar uma operação, o thread copia o valor atualizado da variável para a memória principal e, a partir daí, outros threads podem ler o valor mais recente.

Simplificando, a palavra-chavevolatile marca uma variável para sempre ir para a memória principal, tanto para leituras quanto para gravações, no caso de vários threads acessando-a.

2. Quando usarvolatile

Nas situações em que o próximo valor da variável depende do valor anterior, há uma chance de que vários threads de leitura e gravação da variável fiquem fora de sincronia, devido a um intervalo de tempo entre a leitura e a gravação na memória principal. .

Isso pode ser ilustrado por um exemplo simples:

public class SharedObject {
    private volatile int count = 0;

    public void increamentCount() {
        count++;
    }
    public int getCount() {
        return count;
    }
}

With no synchronization here, a typical race condition can occur. Basicamente, com uma lacuna de execução entre o incremento e a gravação na memória principal, outras threads podem ver um valor de 0 e tentar gravá-lo na memória principal.

A condição de corrida também pode ser evitada com o uso dos tipos de dados atômicos fornecidos pelo Java, comoAtomicInt ouAtomicLong.

3. Sincronização volátil e thread

Para todos os aplicativos multithread, precisamos garantir algumas regras para um comportamento consistente:

  • Exclusão mútua - apenas um thread executa uma seção crítica por vez

  • Visibilidade - alterações feitas por um thread nos dados compartilhados, são visíveis para outros threads para manter a consistência dos dados

Os métodos e blocosSynchronized fornecem ambas as propriedades acima, às custas do desempenho do aplicativo.

Volatile é uma primitiva bastante útil porquecan help ensure the visibility aspect of the data change, without, of course, providing the mutual exclusion. Assim, é útil em lugares onde estamos ok com vários threads executando um bloco de código em paralelo, mas precisamos garantir a propriedade de visibilidade.

4. Garantia acontece antes

Começando com Java 5, a palavra-chavevolatile também fornece recursos adicionais que garantem que os valores de todas as variáveis, incluindo variáveis ​​não voláteis, sejam gravados na memória principal junto com a operação de gravaçãoVolatile.

Isso se chama Happens-Before, pois fornece uma visibilidade de todas as variáveis ​​para outro segmento de leitura. Além disso, a JVM não reordena as instruções de leitura e escrita das variáveisvolatile.

Vamos dar uma olhada no exemplo:

Thread 1
    object.aNonValitileVariable = 1;
    object.aVolatileVariable = 100; // volatile write

Thread 2:
    int aNonValitileVariable = object.aNonValitileVariable;
    int aVolatileVariable =  object.aVolatileVariable;

Nesse caso, quandoThread 1 escreveu o valor deaVolatileVariable, o valor deaNonValitileVariable também é gravado na memória principal. And even though it’s not a volatile variable, it is exhibiting a volatile behavior.

Fazendo uso dessa semântica, podemos definir apenas algumas das variáveis ​​em nossa classe comovolatilee otimizar a garantia de visibilidade.

5. Conclusão

Neste tutorial, exploramos mais sobre a palavra-chavevolatile e seus recursos, bem como as melhorias feitas a partir do Java 5.

Como sempre, os exemplos de código podem ser encontradosover on GitHub.