Wenn das folgende Snippet Ausführen ich sehe, dass die Ergebnisse richtig sind immer und eindeutig inkrementierten jedoch sind sie in der falschen Reihenfolge gedruckt (siehe unten):Garantieren Atom in Java Ordnung oder nur Eindeutigkeit?
import java.util.concurrent.atomic.AtomicInteger;
public class Atomics {
private AtomicInteger index = new AtomicInteger(0);
public static void main(String [] args) {
new Atomics().updateIndexViaCAS();
}
private void updateIndexViaCAS() {
Runnable target =() -> {
for(int i = 0; i<10;i++) {
cas:
while (true) {
int oldValue = index.get();
int newValue = oldValue + 1;
if(index.compareAndSet(oldValue, newValue)) {
System.out.println(Thread.currentThread() + ": "+newValue); //order is not guaranteed?
break cas;
}
}
}
};
/*Runnable target =() -> {
for (int i = 0; i < 10; i++) {
int oldValue = index.get();
int newValue = oldValue + 1;
do {
oldValue = index.get();
} while (!index.compareAndSet(oldValue, newValue));
System.out.println(Thread.currentThread() + ": "+newValue);
}
};*/
for(int t=0; t<2;t++) {
Thread th = new Thread(target);
th.start();
}
}
}
Probenergebnisse:
Thread[Thread-0,5,main]: 1
Thread[Thread-0,5,main]: 3
Thread[Thread-0,5,main]: 4
Thread[Thread-0,5,main]: 5
Thread[Thread-0,5,main]: 6
Thread[Thread-1,5,main]: 2 <-- out of order
Thread[Thread-0,5,main]: 7
Thread[Thread-0,5,main]: 9
Thread[Thread-0,5,main]: 10
Thread[Thread-0,5,main]: 11
Thread[Thread-0,5,main]: 12
Thread[Thread-1,5,main]: 8 <-- out of order
Thread[Thread-1,5,main]: 13
Thread[Thread-1,5,main]: 14
Thread[Thread-1,5,main]: 15
Thread[Thread-1,5,main]: 16
Thread[Thread-1,5,main]: 17
Thread[Thread-1,5,main]: 18
Thread[Thread-1,5,main]: 19
Thread[Thread-1,5,main]: 20
Ist es weil:
Es ist etwas falsch mit dem Code (und wenn ja, wie es zu beheben, um die Bestellung zu erzwingen)?
Ist es das richtige Verhalten von Atomics, weil sie vom Design her nicht die Ausführungsreihenfolge garantieren, sondern nur die Lockless-Concurrency garantieren?
Gibt es noch etwas anderes hier?
TIA.
Um meine Verwirrung mit den Kommentaren unten zu beheben - warum sollte ich die Atomics in erster Linie brauchen, wenn ich noch Synchronisation verwenden muss, um zu sehen, was unten so weitergeht?
Runnable target =() -> {
for (int i = 0; i < 10; i++) {
cas: while (true) {
synchronized (mutex) {
int oldValue = index.get();
int newValue = oldValue + 1;
if (index.compareAndSet(oldValue, newValue)) {
System.out.println(Thread.currentThread() + ": "
+ newValue); // order is not guaranteed?
break cas;
}
}
}
}
};
Die Reihenfolge, in der "index" seine Werte annimmt, ist nicht unbedingt die Reihenfolge, in der die 'println' Aufrufe auftreten.' CompareAndSet' ist atomar; 'compareAndSet'-and-println ist nicht. – user2357112
Es ist # 2. Atomare Variablen erzwingen die Atomizität von Updates und die Speichersichtbarkeit von Updates. Sie haben nichts mit Bestellungen zu tun. –
@ 4castle: Also, bedeutet es, dass das atomare CAS wirklich nichts kauft, da ich noch synchronisieren muss, um zu sehen, was ich über 'println' sehen möchte? Oder was? Beispiele für Code werden geschätzt. –