Was bedeutet "atomar" in der Programmierung?

273

Im Buch "Effective Java" heißt es:

Die Sprachspezifikation garantiert, dass das Lesen oder Schreiben einer Variablen atomar ist, es sei denn, die Variable ist vom Typ longoder double[JLS, 17.4.7].

Was bedeutet "atomar" im Kontext der Java-Programmierung oder der Programmierung im Allgemeinen?

James
quelle
24
Jeweils eine Operation.
Subhrajyoti Majumder
1
Es kann jeweils nur eine Operation für die Variable ausgeführt werden.
Kaysush
1
Ich vermute , dass Philosophie Fragen gehören in codereview.stackexchange.com
Phlip
Beachten Sie, dass einige Variablen standardmäßig kein atomares Lesen und Schreiben haben, und deklarieren sie als volatile longoder volatile doublemachen das Lesen atomar und das Schreiben atomar.
H2ONaCl

Antworten:

372

Hier ist ein Beispiel, weil ein Beispiel oft klarer ist als eine lange Erklärung. Angenommen, es foohandelt 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 foound 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 foovor 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;
JB Nizet
quelle
75
Dies setzt also voraus, dass es in einem 32-Bit-System ausgeführt wird. Was wäre, wenn es ein 64-Bit-System wäre? Will foo = 65465498L; dann atomar sein?
Harke
46
@ Harke Wenn Sie 64-Bit-Java ausführen, ja.
Jeroen
4
Gilt dies auch für C # und .NET? Wenn ja, um foo ein atomares Verhalten zu erhalten, muss die CLR 64-Bit sein?
Fabiano
5
@Fabiano Es gilt und hier erfahren Sie, wie Sie es in .NET erreichen, da wir nicht das synchronisierte Schlüsselwort wie Java haben. stackoverflow.com/questions/541194/…
Der Muffin-Mann
2
Nehmen wir dann an, dass Thread A einen langen Wert zuweist und Thread B auf halbem Weg versucht, ihn zu lesen. Wenn Operation A atomar ist, wartet Thread B, bis er beendet ist. Dies bedeutet, dass atomare Operationen implizite Thread-Sicherheit bieten?
Teoman Shipahi
60

"Atomoperation" bezeichnet eine Operation, die aus der Sicht aller anderen Threads augenblicklich zu sein scheint. Sie müssen sich keine Gedanken über einen teilweise vollständigen Vorgang machen, wenn die Garantie gilt.

H2ONaCl
quelle
25

Es ist etwas, das "dem Rest des Systems augenblicklich erscheint" und unter die Kategorisierung der Linearisierbarkeit in Rechenprozessen fällt . Um diesen verlinkten Artikel weiter zu zitieren:

Atomizität ist eine Garantie für die Isolation von gleichzeitigen Prozessen. Darüber hinaus haben atomare Operationen üblicherweise eine Erfolgs- oder Fehlerdefinition - sie ändern entweder erfolgreich den Status des Systems oder haben keine offensichtlichen Auswirkungen.

So kann es beispielsweise im Kontext eines Datenbanksystems zu "atomaren Commits" kommen, was bedeutet, dass Sie einen Änderungssatz von Aktualisierungen in eine relationale Datenbank übertragen können und diese Änderungen entweder alle oder gar nicht übermittelt werden Fall des Scheiterns, nicht auf dieser Weise Daten nicht beschädigt werden, und Folge von Schlössern und / oder Warteschlangen, die nächste Operation eine andere Schreib- oder ein Lese sein, aber nur nach der Tatsache. Im Zusammenhang mit Variablen und Threading ist dies im Hinblick auf den Speicher ähnlich.

Ihr Angebot hebt hervor , dass dieser Bedarf nicht Verhalten in allen Fällen zu erwarten.

Grant Thomas
quelle
15

Ich habe gerade einen Beitrag Atomic vs. Non-Atomic Operations gefunden , der mir sehr hilfreich ist.

"Eine Operation, die auf den gemeinsam genutzten Speicher wirkt, ist atomar, wenn sie in einem einzigen Schritt relativ zu anderen Threads ausgeführt wird.

Wenn ein Atomspeicher in einem gemeinsam genutzten Speicher ausgeführt wird, kann kein anderer Thread beobachten, dass die Änderung zur Hälfte abgeschlossen ist.

Wenn eine atomare Last für eine gemeinsam genutzte Variable ausgeführt wird, liest sie den gesamten Wert so, wie er zu einem bestimmten Zeitpunkt angezeigt wurde. "

Kurt Zhong
quelle
14

Wenn Sie mehrere Threads haben, die die Methoden m1 und m2 im folgenden Code ausführen:

class SomeClass {
    private int i = 0;

    public void m1() { i = 5; }
    public int m2() { return i; }
}

Sie haben die Garantie, dass jeder Thread-Aufruf m2entweder 0 oder 5 lautet.

Auf der anderen Seite mit diesem Code (wo iist ein langer):

class SomeClass {
    private long i = 0;

    public void m1() { i = 1234567890L; }
    public long m2() { return i; }
}

Ein Thread-Aufruf m2könnte 0, 1234567890L oder einen anderen zufälligen Wert lesen, da i = 1234567890Lnicht garantiert wird, dass die Anweisung für a atomar ist long(eine JVM könnte die ersten 32 Bits und die letzten 32 Bits in zwei Operationen schreiben und ein Thread könnte idazwischen beobachten ). .

Assylien
quelle
Warum verursacht "long" Ihrer Meinung nach ein Problem, während "int" dies nicht tut? Bitte sehen Sie hier geekswithblogs.net/BlackRabbitCoder/archive/2012/08/09/…
onmyway133
1
@entropy lange und doppelte Zuweisungen sind in Java nicht garantiert atomar. Sie können also einen Long lesen, bei dem nur die Hälfte der Bits nach einer Zuweisung aktualisiert wurde.
Assylias
0

In Java treten Lese- und Schreibfelder aller Art außer long und double atomar auf, und wenn das Feld mit dem flüchtigen Modifikator deklariert wird, werden auch long und double atomar gelesen und geschrieben. Das heißt, wir erhalten zu 100% entweder das, was dort war oder was dort passiert ist, und es kann auch kein Zwischenergebnis in den Variablen geben.

Eugene Shamkin
quelle