¿Por qué i++no es atómico en Java?
Para profundizar un poco más en Java, traté de contar con qué frecuencia se ejecuta el bucle en los subprocesos.
Entonces usé un
private static int total = 0;
en la clase principal.
Tengo dos hilos.
- Hilo 1: Impresiones
System.out.println("Hello from Thread 1!"); - Hilo 2: Impresiones
System.out.println("Hello from Thread 2!");
Y cuento las líneas impresas por el hilo 1 y el hilo 2. Pero las líneas del hilo 1 + las líneas del hilo 2 no coinciden con el número total de líneas impresas.
Aquí está mi código:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Test {
private static int total = 0;
private static int countT1 = 0;
private static int countT2 = 0;
private boolean run = true;
public Test() {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
newCachedThreadPool.execute(t1);
newCachedThreadPool.execute(t2);
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
run = false;
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println((countT1 + countT2 + " == " + total));
}
private Runnable t1 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT1++;
System.out.println("Hello #" + countT1 + " from Thread 2! Total hello: " + total);
}
}
};
private Runnable t2 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT2++;
System.out.println("Hello #" + countT2 + " from Thread 2! Total hello: " + total);
}
}
};
public static void main(String[] args) {
new Test();
}
}
iincoperación para incrementar enteros, pero eso solo funciona para variables locales, donde la concurrencia no es una preocupación. Para los campos, el compilador genera comandos de lectura, modificación y escritura por separado.
iincinstrucción para los campos, que tiene una sola instrucción no garantiza la atomicidad, por ejemplo, no volatile longy doubleel acceso de campo en no garantiza que sea atómica sin tener en cuenta el hecho de que se lleva a cabo por una sola instrucción de código de bytes.
AtomicInteger?