volatile es un modificador de variable que garantiza la visibilidad de los cambios de esta variable a todos los hilos. Si una variable se declara como volatile, su lectura y escritura se realizan directamente desde la memoria principal, evitando las cachés locales de los hilos. Esto previene el almacenamiento en caché de valores localmente en el hilo.
synchronized es una palabra clave que proporciona no solo visibilidad, sino también exclusión mutua: solo un hilo puede ejecutar un bloque sincronizado en un momento dado para un objeto.
Se deben usar variables volatile para banderas simples y contadores, si:
Ejemplo de uso de volatile:
class Flag { private volatile boolean running = true; public void stop() { running = false; } public void loop() { while (running) { // ... } } }
¿Se puede usar volatile para garantizar la atomicidad de la operación de incremento de una variable?
Respuesta:
No, volatile no garantiza la atomicidad de las operaciones. Por ejemplo, counter++ no es atómico incluso si counter se declara como volatile, porque la operación involucra lectura, modificación y escritura (varias acciones) que pueden ser interrumpidas por otro hilo. La atomicidad se garantiza mediante synchronized o clases del paquete java.util.concurrent.atomic.
Ejemplo:
class Counter { private volatile int count = 0; public void increment() { count++; // ¡NO es una operación atómica! } }
Historia
En un proyecto de tienda en línea, la bandera de finalización del hilo de procesamiento de pedidos se implementó sin volatile. Como resultado, uno de los hilos "se atasco" en un ciclo infinito, ya que no veía el cambio de variable realizado desde otro hilo. El diagnóstico tomó varios días.
Historia
En un sistema financiero, un desarrollador utilizó volatile int para un contador de operaciones. En cargas pico, el número de operaciones comenzaba a "perderse". La razón: pérdida de atomicidad en operaciones complejas de incremento.
Historia
Los desarrolladores confundieron volatile y synchronized al intentar usar volatile para garantizar la exclusión mutua del acceso a secciones críticas, lo que llevó a data race y errores difíciles de detectar en una aplicación multihilo.