Perché i++
non è atomico in Java?
Per approfondire Java ho provato a contare la frequenza con cui vengono eseguiti i cicli nei thread.
Quindi ho usato un file
private static int total = 0;
nella classe principale.
Ho due thread.
- Discussione 1: stampe
System.out.println("Hello from Thread 1!");
- Discussione 2: stampe
System.out.println("Hello from Thread 2!");
E conto le righe stampate dal thread 1 e dal thread 2. Ma le righe del thread 1 + le righe del thread 2 non corrispondono al numero totale di righe stampate.
Ecco il mio codice:
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();
}
}
iinc
un'operazione per l'incremento di interi, ma funziona solo per le variabili locali, dove la concorrenza non è un problema. Per i campi, il compilatore genera i comandi di lettura-modifica-scrittura separatamente.
iinc
un'istruzione per i campi, avere una singola istruzione non garantisce l'atomicità, ad esempio l' accesso non volatile
long
e al double
campo non è garantito come atomico indipendentemente dal fatto che sia eseguito da una singola istruzione bytecode.
AtomicInteger
?