Variáveis Atômicas: Atualizações sem Bloqueios
Use AtomicInteger, AtomicLong e AtomicReference para contadores seguros em relação às threads, sem bloqueios.
Variáveis Atômicas: Atualizações sem Bloqueios é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.
O problema das operações não atômicas
O incremento simples count++ NÃO é seguro para uso concorrente — são três operações: ler, adicionar e gravar. Linhas de execução concorrentes podem intercalá-las, causando atualizações perdidas. Variáveis atômicas resolvem isso sem bloqueios.
// UNSAFE:
int count = 0;
// Thread A reads count=0, Thread B reads count=0
// Both write 1 — second update lost!
count++; // NOT thread-safe
// SAFE:
import java.util.concurrent.atomic.*;
AtomicInteger atomicCount = new AtomicInteger(0);
atomicCount.incrementAndGet(); // atomic, lock-freeNoções básicas de AtomicInteger
AtomicInteger fornece operações sobre inteiros que têm garantia de atomicidade usando instruções de comparação e troca (CAS) da CPU — não são necessários bloqueios.
AtomicInteger counter = new AtomicInteger(0);
counter.set(10); // set to 10
System.out.println(counter.get()); // 10
int prev = counter.getAndIncrement(); // returns 10, sets to 11
int curr = counter.incrementAndGet(); // sets to 12, returns 12
counter.addAndGet(5); // adds 5, returns 17
counter.decrementAndGet(); // subtracts 1, returns 16compareAndSet: a operação CAS
compareAndSet(expected, update) atualiza o valor atomicamente somente se ele for atualmente igual ao valor esperado. Retorna true se for bem-sucedido. Essa é a base de todos os algoritmos sem bloqueios.
AtomicInteger ai = new AtomicInteger(5);
boolean updated = ai.compareAndSet(5, 10); // current==5? set to 10
System.out.println(updated); // true
System.out.println(ai.get()); // 10
boolean failed = ai.compareAndSet(5, 20); // current==10, not 5 → fails
System.out.println(failed); // false
System.out.println(ai.get()); // still 10AtomicLong para contadores
AtomicLong é o equivalente de 64 bits. É comum em geradores de sequências e contadores de acertos:
AtomicLong seq = new AtomicLong(0);
// Thread-safe sequence generator:
long nextId() {
return seq.incrementAndGet();
}
System.out.println(nextId()); // 1
System.out.println(nextId()); // 2
System.out.println(nextId()); // 3AtomicBoolean
Sinalizador booleano seguro para uso concorrente. É usado com frequência para inicialização única ou sinais de encerramento:
AtomicBoolean initialized = new AtomicBoolean(false);
void initOnce() {
// compareAndSet: only first caller succeeds
if (initialized.compareAndSet(false, true)) {
System.out.println("Initializing...");
// perform expensive init
} else {
System.out.println("Already initialized");
}
}AtomicReference
AtomicReference<V> fornece atualizações atômicas para uma referência de objeto. É usado para implementar estruturas de dados sem bloqueios:
import java.util.concurrent.atomic.*;
record Config(String host, int port) {}
AtomicReference<Config> configRef =
new AtomicReference<>(new Config("localhost", 8080));
// Hot-swap the configuration atomically:
Config oldConfig = configRef.get();
Config newConfig = new Config("prod.example.com", 443);
boolean swapped = configRef.compareAndSet(oldConfig, newConfig);
System.out.println(swapped); // true
System.out.println(configRef.get()); // Config[host=prod.example.com, port=443]updateAndGet / getAndUpdate
Aplique uma função atomicamente usando internamente um ciclo de novas tentativas de CAS:
AtomicInteger value = new AtomicInteger(10);
// Apply function atomically: square the value
int newVal = value.updateAndGet(x -> x * x);
System.out.println(newVal); // 100
// Get old, then apply:
int old = value.getAndUpdate(x -> x + 1);
System.out.println(old); // 100
System.out.println(value.get()); // 101accumulateAndGet
Combine o valor atual com um valor fornecido usando uma função:
AtomicInteger max = new AtomicInteger(0);
// Keep running maximum:
max.accumulateAndGet(42, Math::max); // max(0, 42) = 42
max.accumulateAndGet(15, Math::max); // max(42, 15) = 42
max.accumulateAndGet(99, Math::max); // max(42, 99) = 99
System.out.println(max.get()); // 99LongAdder para contadores com alta contenção
Sob alta contenção entre linhas de execução, as novas tentativas de CAS de AtomicLong podem prejudicar o desempenho. LongAdder usa várias células para reduzir a contenção:
import java.util.concurrent.atomic.*;
LongAdder adder = new LongAdder();
// Multiple threads can call add() with minimal contention:
adder.increment();
adder.add(5);
adder.increment();
System.out.println(adder.sum()); // 7
// Note: sum() is NOT atomic with add() — use only when no concurrent addsMatrizes atômicas
AtomicIntegerArray / AtomicLongArray fornecem operações atômicas sobre elementos individuais de uma matriz:
AtomicIntegerArray arr = new AtomicIntegerArray(5);
arr.set(0, 10);
arr.incrementAndGet(0);
arr.compareAndSet(2, 0, 42); // index 2: if 0, set 42
System.out.println(arr.get(0)); // 11
System.out.println(arr.get(2)); // 42Quando usar tipos atômicos em vez de bloqueios
Use variáveis atômicas quando:
- Forem necessárias atualizações de uma única variável (contadores, sinalizadores e referências)
- Houver baixa contenção
- O desempenho sem bloqueios for importante
Use bloqueios quando:
- Várias variáveis precisarem ser atualizadas atomicamente
- For necessária uma lógica condicional complexa
- Houver contenção muito alta (as novas tentativas de CAS prejudicam o desempenho)
Verificação rápida
O que compareAndSet(expected, update) garante?
Recapitulação: variáveis atômicas
Principais conclusões:
- Os tipos atômicos usam instruções CAS da CPU — são seguros para uso concorrente e não usam bloqueios
- AtomicInteger/Long/Boolean/Reference fornecem atomicidade para uma única variável
- compareAndSet é a base dos algoritmos sem bloqueios
- updateAndGet/accumulateAndGet permitem atualizações funcionais
- LongAdder é indicado para cenários de contadores com alta contenção
Perguntas Frequentes
A aula “Variáveis Atômicas: Atualizações sem Bloqueios” é grátis?
Sim — o texto completo de “Variáveis Atômicas: Atualizações sem Bloqueios” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.
O que vou aprender em “Variáveis Atômicas: Atualizações sem Bloqueios”?
Use AtomicInteger, AtomicLong e AtomicReference para contadores seguros em relação às threads, sem bloqueios. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Java Academy?
Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Variáveis Atômicas: Atualizações sem Bloqueios”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Java Academy?
Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- ReentrantLock versus synchronized
- ReadWriteLock em Cenários de Leitura e Escrita
- Variáveis Atômicas: Atualizações sem Bloqueios
- StampedLock e Leituras Otimistas