Für Ihr spezielles Beispiel: Wenn die Server-JVM nicht als flüchtig deklariert wird, kann sie die keepRunning
Variable aus der Schleife herausheben, da sie in der Schleife nicht geändert wird (wodurch sie in eine Endlosschleife umgewandelt wird), die Client-JVM jedoch nicht. Deshalb sehen Sie unterschiedliche Ergebnisse.
Es folgt eine allgemeine Erklärung zu flüchtigen Variablen:
Wenn ein Feld deklariert wird volatile
, werden der Compiler und die Laufzeit darauf hingewiesen, dass diese Variable gemeinsam genutzt wird und dass Operationen daran nicht mit anderen Speicheroperationen neu angeordnet werden sollten. Flüchtige Variablen werden nicht in Registern oder in Caches zwischengespeichert, in denen sie vor anderen Prozessoren verborgen sind. Daher gibt ein Lesevorgang einer flüchtigen Variablen immer den letzten Schreibvorgang eines Threads zurück .
Die Sichtbarkeitseffekte flüchtiger Variablen gehen über den Wert der flüchtigen Variablen selbst hinaus. Wenn Thread A in eine flüchtige Variable schreibt und anschließend Thread B dieselbe Variable liest, werden die Werte aller Variablen, die vor dem Schreiben in die flüchtige Variable für A sichtbar waren, nach dem Lesen der flüchtigen Variablen für B sichtbar.
Die häufigste Verwendung für flüchtige Variablen ist die Vervollständigung, Unterbrechung oder das Statusflag:
volatile boolean flag;
while (!flag) {
}
Flüchtige Variablen können für andere Arten von Statusinformationen verwendet werden. Bei diesem Versuch ist jedoch mehr Sorgfalt erforderlich. Beispielsweise ist die Semantik von flüchtig nicht stark genug, um die Inkrementoperation ( count++
) atomar zu machen, es sei denn, Sie können garantieren, dass die Variable nur von einem einzelnen Thread geschrieben wird.
Das Verriegeln kann sowohl Sichtbarkeit als auch Atomizität garantieren. flüchtige Variablen können nur die Sichtbarkeit garantieren.
Sie können flüchtige Variablen nur verwenden, wenn alle folgenden Kriterien erfüllt sind:
- Schreibvorgänge in die Variable hängen nicht von ihrem aktuellen Wert ab, oder Sie können sicherstellen, dass nur ein einzelner Thread den Wert jemals aktualisiert.
- Die Variable nimmt nicht an Invarianten mit anderen Zustandsvariablen teil. und
- Das Sperren ist aus keinem anderen Grund erforderlich, während auf die Variable zugegriffen wird.
Debugging-Tipp : -server
Geben Sie beim Aufrufen der JVM auch beim Entwickeln und Testen immer den JVM-Befehlszeilenschalter an. Die Server-JVM führt mehr Optimierungen durch als die Client-JVM, z. B. das Hochheben von Variablen aus einer Schleife, die in der Schleife nicht geändert werden. Code, der möglicherweise in der Entwicklungsumgebung (Client-JVM) funktioniert, kann in der Bereitstellungsumgebung (Server-JVM) beschädigt werden.
Dies ist ein Auszug aus "Java Concurrency in Practice" , dem besten Buch, das Sie zu diesem Thema finden können.