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-freeFundamentos 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 16compareAndSet: 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 10AtomicLong 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()); // 3AtomicBoolean
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()); // 101accumulateAndGet
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()); // 99LongAdder 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 addsMatrices 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)); // 42Cuá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
- ReentrantLock frente a synchronized
- ReadWriteLock para escenarios de lectores y escritores
- Variables atómicas: actualizaciones sin bloqueo
- StampedLock y lecturas optimistas