Historia del tema:
Cuando Java apareció, no existía una descripción formal de cómo la memoria y los hilos interactúan entre sí. Como resultado, los mismos programas podían comportarse de manera diferente en diferentes JVM, lo que conducía a errores difíciles de detectar. En 2004, se añadió el Modelo de Memoria de Java (JMM) a la especificación de Java, con el objetivo de definir estrictamente cómo los hilos ven las actualizaciones de las variables.
Problema:
Sin un modelo de memoria claro, las operaciones de escritura y lectura pueden ser mezcladas por el compilador o el procesador, lo que conduce a comportamientos inesperados al acceder a variables compartidas desde diferentes hilos. Esto puede causar condiciones de carrera, problemas de visibilidad y errores de sincronización difíciles de depurar.
Solución:
El JMM define reglas: cuándo los cambios realizados por un hilo se vuelven visibles para otros. Establece conceptos como happens-before, sincronizadores (synchronized, volatile, final), bloqueos internos, y limita la reorganización de instrucciones en un entorno multihilo.
Ejemplo de código:
class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int get() { return count; } }
Características clave:
¿Por qué volatile no hace que las operaciones sean atómicas, sino que solo garantiza la visibilidad?
Volatile garantiza solo la visibilidad de los cambios entre hilos, pero no la atomicidad del cambio. Por ejemplo, incrementar una variable volatile no es una operación atómica, ya que la acción en sí consiste en leer, modificar y escribir.
Ejemplo de código:
volatile int count = 0; count++; // ¡No es atómico!
¿Puede un bloque synchronized garantizar la visibilidad de los cambios fuera de él?
Sí. Después de salir de un bloque synchronized, todos los cambios realizados dentro serán visibles para otros hilos que ingresen a un bloque en el mismo objeto monitor.
¿Cuándo son visibles los cambios de los campos final para otros hilos?
Los campos final garantizan una correcta publicación solo si el objeto está completamente construido antes de que se pasen referencias a él a otros hilos, por ejemplo, a través de objetos inmutables. De lo contrario, puede haber visibilidad de un estado no inicializado.
Caso negativo
El desarrollador decidió aumentar el contador de accesos al sitio web mediante un incremento simple volatile desde varios hilos.
Pros:
Contras:
Caso positivo
Se utilizó AtomicInteger para el contador o métodos synchronized.
Pros:
Contras: