0Pricing
Java Academy · Lección

Variables atómicas: actualizaciones sin bloqueo

Use AtomicInteger, AtomicLong y AtomicReference para crear contadores seguros para hilos sin bloqueos.

Variables atómicas: actualizaciones sin bloqueo es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.

El problema de las operaciones no atómicas

El incremento simple count++ NO es seguro para subprocesos: consta de tres operaciones: leer, sumar y escribir. Los subprocesos simultáneos pueden intercalarlas y provocar actualizaciones perdidas. Las variables atómicas resuelven este problema sin bloqueos.

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

Fundamentos de AtomicInteger

AtomicInteger proporciona operaciones con enteros que tienen garantizada la atomicidad mediante instrucciones de comparación e intercambio (CAS) de la CPU, sin necesidad de bloqueos.

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: la operación CAS

compareAndSet(expected, update) actualiza el valor atómicamente solo si actualmente es igual al valor esperado. Devuelve true si la operación se realiza correctamente. Es la base de todos los algoritmos sin bloqueos.

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 es el equivalente de 64 bits. Se usa habitualmente para generadores de secuencias y contadores de accesos:

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

Indicador booleano seguro para subprocesos. Se usa habitualmente para la inicialización única o para indicar el apagado:

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> proporciona actualizaciones atómicas de una referencia a un objeto. Se utiliza para implementar estructuras de datos sin bloqueos:

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 una función atómicamente mediante un bucle interno de reintento 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 el valor actual con un valor proporcionado mediante una función:

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 con alta contención

Con una alta contención entre subprocesos, los reintentos CAS de AtomicLong pueden perjudicar el rendimiento. LongAdder utiliza varias celdas para reducir la contención:

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

Matrices atómicas

AtomicIntegerArray / AtomicLongArray proporcionan operaciones atómicas sobre elementos individuales de una 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

Cuándo usar atómicos frente a bloqueos

Use variables atómicas cuando:

  • Se actualice una sola variable (contadores, indicadores o referencias)
  • Haya poca contención
  • Sea importante el rendimiento sin bloqueos

Use bloqueos cuando:

  • Se deban actualizar varias variables atómicamente
  • Se necesite lógica condicional compleja
  • Haya una contención muy alta (los reintentos CAS perjudican el rendimiento)

Comprobación rápida

¿Qué garantiza compareAndSet(expected, update)?

Resumen: variables atómicas

Conceptos clave:

  • Los tipos atómicos usan instrucciones CAS de la CPU: no tienen bloqueos y son seguros para subprocesos
  • AtomicInteger/Long/Boolean/Reference proporcionan atomicidad para una sola variable
  • compareAndSet es la base de los algoritmos sin bloqueos
  • updateAndGet/accumulateAndGet permiten actualizaciones funcionales
  • LongAdder es adecuado para contadores con alta contención

Preguntas frecuentes

¿La lección «Variables atómicas: actualizaciones sin bloqueo» es gratis?

Sí — el texto completo de «Variables atómicas: actualizaciones sin bloqueo» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Variables atómicas: actualizaciones sin bloqueo»?

Use AtomicInteger, AtomicLong y AtomicReference para crear contadores seguros para hilos sin bloqueos. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Java Academy?

No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Variables atómicas: actualizaciones sin bloqueo»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Java Academy?

Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. ReentrantLock frente a synchronized
  2. ReadWriteLock para escenarios de lectores y escritores
  3. Variables atómicas: actualizaciones sin bloqueo
  4. StampedLock y lecturas optimistas
← Volver a Java Academy