0Pricing
Java Academy · Aula

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-free

Noçõ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 16

compareAndSet: 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 10

AtomicLong 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()); // 3

AtomicBoolean

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()); // 101

accumulateAndGet

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()); // 99

LongAdder 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 adds

Matrizes 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)); // 42

Quando 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

  1. ReentrantLock versus synchronized
  2. ReadWriteLock em Cenários de Leitura e Escrita
  3. Variáveis Atômicas: Atualizações sem Bloqueios
  4. StampedLock e Leituras Otimistas
← Voltar para Java Academy