La atomicidad garantiza que un conjunto de operaciones se ejecuta como una unidad indivisible: todas se completan exitosamente o ninguna se aplica. Un ejemplo clásico es una transferencia bancaria: si la cuenta origen tiene 2000 y se transfieren 800 a una cuenta destino con saldo 0, el proceso implica dos pasos — descontar 800 del origen y sumar 800 al destino. Si ocurre una falla entre medio, el sistema debe revertir la operación; de lo contrario, se perdería dinero. La atomicidad evita precisamente este problema. ### Visibilidad
La visibilidad se refiere a que los cambios realizados por un hilo en variables compartidas sean perceptibles por otros hilos de manera oportuna. El modelo de memoria de Java (JMM) establece que cada hilo mantiene una copia local de las variables compartidas en su memoria de trabajo. Para que exista visibilidad, se deben cumplir dos condiciones: 1. El hilo que modifica debe flushar su copia local hacia la memoria principle. 2. Los demás hilos deben releer la variable desde la memoria principal.
Ejemplo sin synchronized
El siguiente código ilustra qué sucede cuando no se aplica synchronized. Sin esta protección, el resultado puede ser 0 o 50, ya que no hay garantía de que el hilo lector vea los cambios realizados por el hilo escritor. ```
package demo.concurrencia;
public class VisibilidadEjemplo {
private boolean listo = false;
private int calculo = 0;
private int salida = 0;
public void actualizar() {
listo = true;
calculo = 10;
}
public void obtener() {
if (listo) {
salida = calculo * 5;
}
System.out.println("salida = " + salida);
}
class Tarea extends Thread {
private boolean modoEscritura;
public Tarea(boolean escritor) {
this.modoEscritura = escritor;
}
@Override
public void run() {
if (modoEscritura) {
actualizar();
} else {
obtener();
}
}
}
public static void main(String[] args) {
VisibilidadEjemplo instancia = new VisibilidadEjemplo();
instancia.new Tarea(true).start();
instancia.new Tarea(false).start();
}
}
El valor 50 aparece ocasionalmente porque, aunque no exista una garantía formal de visibilidad, el sistema operativo puede planificar los hilos de forma que la copia local se actualice a tiempo. Sin embargo, esto es aleatorio y no debe considerarse un comportamiento confiable. ### Garantizando visibilidad con synchronized
Para asegurar que la salida sea siempre 50, basta con marcar ambos métodos con `synchronized`: ```
public synchronized void actualizar() {
listo = true;
calculo = 10;
}
public synchronized void obtener() {
if (listo) {
salida = calculo * 5;
}
System.out.println("salida = " + salida);
}
Garantizando el orden de ejecución
Además de la visibilidad, necesitamos asegurar que el hilo escritor ejecute antes que el lector. Para ello, introducimos una pequeña pausa entre el lanzamiento de cada hilo: ``` public static void main(String[] args) throws InterruptedException { VisibilidadEjemplo instancia = new VisibilidadEjemplo();
instancia.new Tarea(true).start();
Thread.sleep(100);
instancia.new Tarea(false).start();
}
Con estos cambios, el resultado será consistentemente `salida = 50` en cada ejecución. </div>