Wir wissen, dass die Operationen zum Festlegen von Variablenwerten in Java atomare Operationen sind, mit Ausnahme von Variablen vom Typ Long und Double. Mit anderen Worten, es besteht keine Notwendigkeit, einfache Lese- und Schreiboperationen von Variablenwerten zu synchronisieren.
Vor JVM 1.2 las die Speichermodellimplementierung von Java immer Variablen aus dem Hauptspeicher, was keine besondere Aufmerksamkeit erforderte. Mit der Reife und Optimierung der JVM ist die Verwendung flüchtiger Schlüsselwörter in Multithread-Umgebungen sehr wichtig geworden. Unter dem aktuellen Java-Speichermodell können Threads Variablen im lokalen Speicher (z. B. Maschinenregistern) speichern, anstatt sie direkt im Hauptspeicher zu lesen und zu schreiben. Dies kann dazu führen, dass ein Thread den Wert einer Variablen im Hauptspeicher ändert, während ein anderer Thread weiterhin seine Kopie des Variablenwerts im Register verwendet, was zu Dateninkonsistenzen führt. Um dieses Problem zu lösen, müssen Sie die Variable nur wie in diesem Programm als flüchtig (instabil) deklarieren. Dies zeigt der JVM an, dass diese Variable bei jeder Verwendung zum Lesen im Hauptspeicher gespeichert wird. Allgemein gesprochen
Daher sollten in einer Multitasking-Umgebung Flags, die von Aufgaben gemeinsam genutzt werden, mit volatile geändert werden.
Jedes Mal, wenn ein Thread auf eine durch Volatile geänderte Mitgliedsvariable zugreift, muss der Wert der Mitgliedsvariablen erneut aus dem gemeinsam genutzten Speicher gelesen werden. Wenn sich eine Mitgliedsvariable ändert, ist der Thread außerdem gezwungen, den geänderten Wert zurück in den gemeinsam genutzten Speicher zu schreiben. Auf diese Weise sehen zwei verschiedene Threads jederzeit denselben Wert einer Mitgliedsvariablen.
In der Java-Sprachspezifikation heißt es: Für eine optimale Geschwindigkeit dürfen Threads nur dann private Kopien gemeinsam genutzter Mitgliedsvariablen speichern und diese mit den ursprünglichen Werten der gemeinsam genutzten Mitgliedsvariablen vergleichen, wenn der Thread einen synchronisierten Codeblock betritt oder verlässt.
Wenn mehrere Threads gleichzeitig mit einem Objekt interagieren, muss daher darauf geachtet werden, dass die Threads Änderungen an gemeinsam genutzten Mitgliedsvariablen rechtzeitig erhalten.
Das Schlüsselwort volatile fordert die VM auf: Sie kann keine private Kopie dieser Mitgliedsvariablen speichern, sondern sollte direkt mit der gemeinsam genutzten Mitgliedsvariablen interagieren.
Verwendungsvorschlag: Verwenden Sie volatile für Mitgliedsvariablen, auf die von zwei oder mehr Threads zugegriffen wird. Die Verwendung ist nicht erforderlich, wenn sich die Variable, auf die zugegriffen werden soll, bereits in einem synchronisierten Codeblock befindet oder eine Konstante ist.
Da die Verwendung von volatile die notwendige Codeoptimierung in der VM blockiert, ist sie weniger effizient, sodass dieses Schlüsselwort nur bei Bedarf verwendet werden darf.
Bei der Implementierung der virtuellen Maschine sind Grundtypen wie int und char ein Wort lang. Und long und double nehmen die Länge von zwei Wörtern ein. In einigen Implementierungen virtueller Maschinen können die beiden Wortlängen als zwei atomare Einzelwortlängen behandelt werden.
Wenn Long und Double nicht mit Volatile geändert werden und mehrere Threads auf die Variable zugreifen, ist das Ergebnis aufgrund der allgemeinen Nichtatomarität der Long-Operation verwirrend.
Beispiel: int, ein Thread schreibt 4 und ein anderer schreibt 5. Der Endwert muss 4 oder 5 sein. Und der lange Typ kann ein chaotischer Wert sein.