palavra-chave volatile em Java
A palavra-chave volatile
em Java é usada para indicar que o valor de uma variável será modificado por diferentes threads. Ele garante que as alterações em uma variável sejam sempre visíveis para outros threads, evitando problemas de cache de thread.
Uso
A palavra-chave volatile
é usada principalmente em programação com vários threads para garantir que as atualizações de uma variável sejam propagadas de forma previsível entre os threads.
Sintaxe
volatile dataType variableName;
dataType
: O tipo da variável (por exemplo,int
,boolean
, etc.).variableName
: O nome da variável.
Exemplos
Exemplo 1: Uso básico
public class VolatileExample extends Thread {
private volatile boolean running = true;
public void run() {
while (running) {
// Thread is running
}
System.out.println("Thread stopped.");
}
public void stopRunning() {
running = false;
}
public static void main(String[] args) throws InterruptedException {
VolatileExample thread = new VolatileExample();
thread.start();
Thread.sleep(1000);
thread.stopRunning();
thread.join();
}
}
Neste exemplo, a variável running
está marcada como volatile
. O método run
verifica a variável running
em um loop. O método stopRunning
define running
como false
, o que interrompe o loop. A palavra-chave volatile
garante que as alterações em running
sejam imediatamente visíveis para o método run
.
Exemplo 2: Volátil com vários segmentos
public class VolatileCounter {
private volatile int counter = 0;
public void increment() {
counter++;
}
public int getCounter() {
return counter;
}
public static void main(String[] args) throws InterruptedException {
VolatileCounter vc = new VolatileCounter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
vc.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Counter value: " + vc.getCounter());
}
}
Neste exemplo, a variável counter
está marcada como volatile
. Dois threads incrementam a variável counter
ao mesmo tempo. A palavra-chave volatile
garante que cada thread veja o valor mais recente de counter
.
Dicas e práticas recomendadas
- Garantia de visibilidade: Use
volatile
para garantir a visibilidade das alterações nas variáveis entre os threads. Ele garante que uma leitura de uma variável volátil sempre retorne a gravação mais recente de qualquer thread. - Atomicidade:
volatile
não garante a atomicidade. Para ações compostas (por exemplo, operações de incremento), considere o uso de outros mecanismos de sincronização, como blocossynchronized
ouAtomicInteger
.private AtomicInteger counter = new AtomicInteger(0); counter.incrementAndGet();
- Casos de uso: Adequado para sinalizadores, variáveis de estado e outras variáveis em que o valor mais recente é crítico, mas não são necessárias operações compostas.
- Evite o uso excessivo: O uso excessivo do site
volatile
pode levar a problemas de desempenho. Use-o somente quando necessário para garantir a visibilidade. - Combine com outra sincronização: Em cenários complexos, combine o
volatile
com outros mecanismos de sincronização para garantir a visibilidade e a atomicidade.private volatile boolean flag = false; synchronized (this) { flag = true; }
- Consistência da memória: A palavra-chave
volatile
ajuda a evitar erros de consistência de memória ao estabelecer uma relação happens-before, garantindo que as alterações em uma variável volátil sejam visíveis para outros threads.