Warum ist i++
Java nicht atomar?
Um etwas tiefer in Java einzusteigen, habe ich versucht zu zählen, wie oft die Schleife in Threads ausgeführt wird.
Also habe ich eine verwendet
private static int total = 0;
in der Hauptklasse.
Ich habe zwei Threads.
- Thread 1: Drucke
System.out.println("Hello from Thread 1!");
- Thread 2: Drucke
System.out.println("Hello from Thread 2!");
Und ich zähle die Zeilen, die von Thread 1 und Thread 2 gedruckt wurden. Aber die Zeilen von Thread 1 + Zeilen von Thread 2 stimmen nicht mit der Gesamtzahl der ausgedruckten Zeilen überein.
Hier ist mein Code:
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
Operation zum Inkrementieren von Ganzzahlen, die jedoch nur für lokale Variablen funktioniert, bei denen die Parallelität keine Rolle spielt. Für Felder generiert der Compiler Lese-, Änderungs- und Schreibbefehle separat.
iinc
Anweisung für Felder gab, garantiert eine einzelne Anweisung keine Atomizität, z. B. Nicht- volatile
long
und Feldzugriff ist double
nicht garantiert atomar, unabhängig davon, dass sie von einer einzelnen Bytecode-Anweisung ausgeführt wird.
AtomicInteger
?