Hier ist ein Beispiel, weil ein Beispiel oft klarer ist als eine lange Erklärung. Angenommen, es foo
handelt sich um eine Variable vom Typ long
. Die folgende Operation ist keine atomare Operation:
foo = 65465498L;
In der Tat wird die Variable unter Verwendung von zwei getrennten Operationen geschrieben: eine, die die ersten 32 Bits schreibt, und eine zweite, die die letzten 32 Bits schreibt. Dies bedeutet, dass ein anderer Thread möglicherweise den Wert von liest foo
und den Zwischenzustand anzeigt.
Um die Operation atomar zu machen, müssen Synchronisationsmechanismen verwendet werden, um sicherzustellen, dass die Operation von jedem anderen Thread aus als eine einzelne atomare Operation (dh nicht in Teile teilbar) betrachtet wird. Das bedeutet, dass jeder andere Thread, sobald die Operation atomar gemacht wurde, entweder den Wert von foo
vor der Zuweisung oder nach der Zuweisung sieht . Aber niemals den Zwischenwert.
Eine einfache Möglichkeit, dies zu tun, besteht darin, die Variable flüchtig zu machen :
private volatile long foo;
Oder um jeden Zugriff auf die Variable zu synchronisieren:
public synchronized void setFoo(long value) {
this.foo = value;
}
public synchronized long getFoo() {
return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized
Oder um es durch Folgendes zu ersetzen AtomicLong
:
private AtomicLong foo;