Verwenden Sie das Schlüsselwort volatile in Java?

Bei der Arbeit stieß ich heute auf das volatile Schlüsselwort in Java. Da ich mich nicht sehr gut damit auskenne, fand ich diese Erklärung:

Java Theorie und Praxis: Umgang mit Volatilität

Angesichts der Details, in denen dieser Artikel das fragliche Keyword erläutert, verwenden Sie es jemals oder könnten Sie jemals einen Fall sehen, in dem Sie dieses Keyword in der richtigen Weise verwenden könnten?

    volatile hat eine Semantik für die Sichtbarkeit des Speichers. Grundsätzlich wird der Wert eines volatile Feldes für alle Leser (insbesondere andere Threads) sichtbar, nachdem eine Schreiboperation abgeschlossen wurde. Ohne volatile könnten Leser einen nicht aktualisierten Wert sehen.

    Um Ihre Frage zu beantworten: Ja, ich verwende eine volatile Variable, um zu steuern, ob ein Code eine Schleife fortsetzt. Die Schleife testet den volatile Wert und fährt fort, wenn sie true . Die Bedingung kann durch Aufruf einer “stop” -Methode auf false gesetzt werden. Die Schleife erkennt false und wird beendet, wenn der Wert nach Beendigung der Ausführung der Stoppmethode getestet wird.

    Das Buch ” Java Concurrency in Practice “, das ich sehr empfehlen kann, gibt eine gute Erklärung für volatile . Dieses Buch wurde von derselben Person verfasst, die den IBM-Artikel schrieb, auf den in der Frage verwiesen wird (in der Tat zitiert er sein Buch am Ende dieses Artikels). Meine Verwendung von volatile ist, was sein Artikel die “Muster 1 Statusflagge” nennt.

    Wenn Sie mehr darüber erfahren möchten, wie volatile unter der Haube funktioniert, lesen Sie das Java-Speichermodell . Wenn Sie über dieses Niveau hinausgehen wollen, schauen Sie sich ein gutes Computerarchitekturbuch wie Hennessy & Patterson an und lesen Sie über Cache-Kohärenz und Cache-Konsistenz.

    “… der flüchtige Modifikator garantiert, dass jeder Thread, der ein Feld liest, den zuletzt geschriebenen Wert sieht.” – Josh Bloch

    Wenn Sie darüber nachdenken, volatile , lesen Sie das Paket java.util.concurrent das sich mit atomarem Verhalten beschäftigt.

    Der Wikipedia-Post auf einem Singleton-Muster zeigt flüchtige Verwendung.

    Wichtiger Punkt zu volatile :

    1. Die Synchronisierung in Java ist möglich, indem Java-Schlüsselwörter synchronized und volatile und gesperrt werden.
    2. In Java können wir die Variable nicht synchronized . Die Verwendung eines synchronized Schlüsselworts mit einer Variablen ist unzulässig und führt zu einem Kompilierungserrors. Anstatt die synchronized Variable in Java zu verwenden, können Sie die Variable java volatile , die JVM-Threads anweist, den Wert der volatile Variablen aus dem Hauptspeicher zu lesen und sie nicht lokal zwischenzuspeichern.
    3. Wenn eine Variable nicht zwischen mehreren Threads geteilt wird, muss das Schlüsselwort volatile .

    Quelle

    Beispielhafte Verwendung von volatile :

     public class Singleton { private static volatile Singleton _instance; // volatile variable public static Singleton getInstance() { if (_instance == null) { synchronized (Singleton.class) { if (_instance == null) _instance = new Singleton(); } } return _instance; } } 

    Wir erstellen Instanz faul zum Zeitpunkt der ersten Anfrage.

    Wenn wir die Variable _instance volatile der Thread, der die Instanz von Singleton nicht mit dem anderen Thread kommunizieren. Wenn Thread A eine Singleton-Instanz erstellt und direkt nach der Erstellung die CPU usw. korrumpiert, können alle anderen Threads den Wert von _instance nicht als null erkennen und glauben, dass ihm immer noch null zugewiesen wird.

    Warum passiert das? Da Reader-Threads keine Sperren ausführen und der Writer-Thread nicht aus einem synchronisierten Block stammt, wird der Speicher nicht synchronisiert und der Wert von _instance wird nicht im Hauptspeicher aktualisiert. Mit dem Volatile-Schlüsselwort in Java wird dies von Java selbst gehandhabt und solche Aktualisierungen sind für alle Leser-Threads sichtbar.

    Fazit : volatile Schlüsselwort wird auch verwendet, um den Inhalt des Speichers zwischen Threads zu kommunizieren.

    Beispielhafte Verwendung von ohne volatile:

     public class Singleton{ private static Singleton _instance; //without volatile variable public static Singleton getInstance(){ if(_instance == null){ synchronized(Singleton.class){ if(_instance == null) _instance = new Singleton(); } } return _instance; } 

    Der obige Code ist nicht Thread-sicher. Obwohl der JIT-Compiler den Wert der Instanz innerhalb des synchronisierten Blocks erneut prüft (aus Performance-Gründen), kann der JIT-Compiler den Bytecode so umordnen, dass der Verweis auf die Instanz gesetzt wird, bevor der Konstruktor seine Ausführung beendet hat. Dies bedeutet, dass die Methode getInstance () ein Objekt zurückgibt, das möglicherweise nicht vollständig initialisiert wurde. Um den Code threadsicher zu machen, kann seit Java 5 das Schlüsselwort volatile für die Instanzvariable verwendet werden. Variablen, die als flüchtig markiert sind, werden nur für andere Threads sichtbar, sobald der Konstruktor des Objekts seine Ausführung vollständig beendet hat.
    Quelle

    Bildbeschreibung hier eingeben

    volatile Verwendung in Java :

    Die Fail-Fast-Iteratoren werden typischerweise unter Verwendung eines volatile Zählers auf dem Listenobjekt implementiert.

    • Wenn die Liste aktualisiert wird, wird der Zähler inkrementiert.
    • Wenn ein Iterator erstellt wird, wird der aktuelle Wert des Zählers in das Iterator Objekt eingebettet.
    • Wenn eine Iterator Operation ausgeführt wird, vergleicht die Methode die beiden Zählerwerte und triggers eine ConcurrentModificationException wenn sie unterschiedlich sind.

    Die Implementierung von errorssicheren Iteratoren ist typischerweise gering. Sie beruhen typischerweise auf Eigenschaften der spezifischen Datenstrukturen der Listenimplementierung. Es gibt kein allgemeines Muster.

    volatile ist sehr nützlich, um Threads zu stoppen.

    Nicht, dass Sie eigene Threads schreiben sollten, Java 1.6 hat viele nette Thread-Pools. Aber wenn Sie sicher sind, dass Sie einen Thread benötigen, müssen Sie wissen, wie Sie ihn stoppen können.

    Das Muster, das ich für Threads verwende, ist:

     public class Foo extends Thread { private volatile boolean close = false; public void run() { while(!close) { // do work } } public void close() { close = true; // interrupt here if needed } } 

    Beachten Sie, dass keine Synchronisierung erforderlich ist

    Ein häufiges Beispiel für die Verwendung von volatile ist die Verwendung einer volatile boolean Variablen als Flag zum Beenden eines Threads. Wenn Sie einen Thread gestartet haben und diesen sicher von einem anderen Thread trennen möchten, können Sie den Thread regelmäßig ein Flag überprüfen lassen. Um es zu stoppen, setzen Sie das Flag auf wahr. Indem Sie das Flag volatile , können Sie sicherstellen, dass der Thread, der es überprüft, bei der nächsten Überprüfung des Threads festgestellt wird, ohne dass ein synchronized Block verwendet werden muss.

    Ja, volatile muss immer dann verwendet werden, wenn auf eine veränderbare Variable von mehreren Threads zugegriffen werden soll. Dies ist nicht sehr häufig, da Sie in der Regel mehr als eine atomare Operation ausführen müssen (z. B. den Variablenstatus vor der Änderung überprüfen). In diesem Fall würden Sie stattdessen einen synchronisierten Block verwenden.

    Niemand hat die Behandlung von Lese- und Schreiboperationen für lange und doppelte Variablen erwähnt. Lesen und Schreiben sind atomare Operationen für Referenzvariablen und für die meisten primitiven Variablen, mit Ausnahme langer und doppelter Variablentypen, die das flüchtige Schlüsselwort als atomare Operationen verwenden müssen. @Verknüpfung

    IMO zwei wichtige Szenarien außer Stop Thread, in dem volatile Schlüsselwort verwendet wird, sind

    1. Doppelter Check-Lock-Mechanismus . Wird häufig im Singleton Designmuster verwendet. In diesem singleton object needs to be declared volatile das singleton object needs to be declared volatile .
    2. Falsche Weckrufe . Thread kann manchmal vom Warteaufruf aufwachen, selbst wenn kein Notify-Anruf ausgegeben wurde. Dieses Verhalten wird als Aufwecken bezeichnet. Dem kann mit einer Bedingungsvariablen (boolesches Flag) entgegengewirkt werden. Setzen Sie den Aufruf wait () in eine while-Schleife, solange das Flag wahr ist. Wenn der Thread also aus einem Warteaufruf aus anderen Gründen als notify / notifyall aufwacht, ist das Flag flag immer noch wahr und die Anrufe sind daher erneut zu warten. Vor dem Aufruf von notify setzen Sie dieses Flag auf true. In diesem Fall wird das boolean flag is declared as volatile .

    Eine Variable, die mit einem volatile Schlüsselwort deklariert wurde, hat zwei Haupteigenschaften, die sie besonders machen.

    1. Wenn wir eine flüchtige Variable haben, kann sie nicht von irgendeinem Thread in den Cache-Speicher des Computers (Mikroprozessors) zwischengespeichert werden. Der Zugriff erfolgte immer aus dem Hauptspeicher.

    2. Wenn eine Schreiboperation an einer flüchtigen Variablen vorgeht und plötzlich eine Leseoperation angefordert wird, ist garantiert, dass die Schreiboperation vor der Leseoperation beendet wird .

    Zwei obige Qualitäten folgern daraus

    • Alle Threads, die eine flüchtige Variable lesen, lesen den letzten Wert. Weil kein zwischengespeicherter Wert es verschmutzen kann. Und auch die Leseanforderung wird erst nach dem Abschluss der aktuellen Schreiboperation erteilt.

    Und auf der anderen Seite,

    • Wenn wir weiter die Nummer 2 untersuchen , die ich erwähnt habe, können wir sehen, dass das volatile Schlüsselwort eine ideale Möglichkeit ist, eine gemeinsame Variable zu verwalten, die eine Anzahl von Lese-Threads und nur einen Schreib-Thread für den Zugriff hat. Sobald wir das volatile Schlüsselwort hinzugefügt haben, ist es erledigt. Kein anderer Overhead über die Fadensicherheit.

    Im Gegenteil,

    Wir können das volatile Schlüsselwort nicht allein verwenden, um eine gemeinsam genutzte Variable zu erfüllen, die mehr als einen schreibenden Thread besitzt, der auf sie zugreift .

    Sie müssen das Schlüsselwort “volatile” oder “synchronized” und alle anderen Tools und Techniken zur Steuerung des gemeinsamen Zugriffs verwenden, die Ihnen zur Verfügung stehen, wenn Sie eine Multithread-Anwendung entwickeln. Ein Beispiel für eine solche Anwendung sind Desktop-Apps.

    Wenn Sie eine Anwendung entwickeln, die auf einem Anwendungsserver (Tomcat, JBoss AS, Glassfish usw.) bereitgestellt wird, müssen Sie die Steuerung des gemeinsamen Zugriffs nicht selbst vornehmen, da sie bereits vom Anwendungsserver angesprochen wird. Wenn ich mich richtig erinnere, verbietet der Java-EE-Standard tatsächlich die Kontrolle des gemeinsamen Zugriffs in Servlets und EJBs, da er Teil der ‘Infrastruktur’-Ebene ist, die von der Behandlung befreit werden sollte. Wenn Sie Singleton-Objekte implementieren, führen Sie die Concurrency-Steuerung nur in einer solchen App durch. Dies ist sogar bereits angesprochen, wenn Sie Ihre Komponenten mit Framework wie Spring stricken.

    In den meisten Fällen der Java-Entwicklung, in der die Anwendung eine Webanwendung ist und ein IoC-Framework wie Spring oder EJB verwendet, müssen Sie daher nicht “flüchtig” verwenden.

    volatile garantiert nur, dass alle Threads, selbst sie selbst, inkrementieren. Zum Beispiel: Ein Zähler sieht zur gleichen Zeit die gleiche Seite der Variablen. Es wird nicht anstelle von synchronisierten oder atomaren oder anderen Dingen verwendet, es macht die Lesevorgänge vollständig synchron. Bitte vergleichen Sie es nicht mit anderen Java-Keywords. Wie das Beispiel unten zeigt, sind volatile variable Operationen auch atomar, sie scheitern oder sind auf einmal erfolgreich.

     package io.netty.example.telnet; import java.util.ArrayList; import java.util.List; public class Main { public static volatile int a = 0; public static void main(String args[]) throws InterruptedException{ List list = new ArrayList(); for(int i = 0 ; i<11 ;i++){ list.add(new Pojo()); } for (Thread thread : list) { thread.start(); } Thread.sleep(20000); System.out.println(a); } } class Pojo extends Thread{ int a = 10001; public void run() { while(a-->0){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } Main.a++; System.out.println("a = "+Main.a); } } } 

    Auch wenn Sie volatile oder keine Ergebnisse machen, werden sich die Ergebnisse immer unterscheiden. Aber wenn Sie AtomicInteger wie unten verwenden, werden die Ergebnisse immer gleich sein. Dies gilt auch für synchronisierte.

      package io.netty.example.telnet; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class Main { public static volatile AtomicInteger a = new AtomicInteger(0); public static void main(String args[]) throws InterruptedException{ List list = new ArrayList(); for(int i = 0 ; i<11 ;i++){ list.add(new Pojo()); } for (Thread thread : list) { thread.start(); } Thread.sleep(20000); System.out.println(a.get()); } } class Pojo extends Thread{ int a = 10001; public void run() { while(a-->0){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } Main.a.incrementAndGet(); System.out.println("a = "+Main.a); } } } 

    Ja, ich benutze es ziemlich oft – es kann sehr nützlich für Multi-Thread-Code sein. Der Artikel, auf den Sie hingewiesen haben, ist ein guter. Dabei sind zwei wichtige Dinge zu beachten:

    1. Sie sollten flüchtig nur verwenden, wenn Sie vollständig verstehen, was es tut und wie es sich von synchronisiert unterscheidet. In vielen Situationen erscheint Volatilität oberflächlich gesehen als eine einfachere, performantere Alternative zur Synchronisation, wenn oft ein besseres Verständnis von Volatile verdeutlichen würde, dass die Synchronisation die einzige Option ist, die funktionieren würde.
    2. Volatile funktioniert nicht in vielen älteren JVMs, obwohl synchronisiert. Ich erinnere mich an ein Dokument, das auf die verschiedenen Ebenen der Unterstützung in verschiedenen JVMs verwiesen hat, aber leider kann ich es jetzt nicht finden. Wenn Sie Java Pre 1.5 verwenden oder wenn Sie nicht über die JVMs verfügen, auf denen Ihr Programm ausgeführt wird, sollten Sie unbedingt darauf achten.

    Absolut ja. (Und nicht nur in Java, sondern auch in C #.) Es gibt Zeiten, in denen Sie einen Wert erhalten oder setzen müssen, der garantiert eine atomare Operation auf Ihrer gegebenen Plattform ist, zum Beispiel int oder boolean, aber nicht erforderlich der Overhead der Thread-Verriegelung. Mit dem Schlüsselwort volatile können Sie sicherstellen, dass beim Lesen des Werts, dass Sie den aktuellen Wert erhalten, und nicht eines zwischengespeicherten Werts, der gerade durch einen Schreibvorgang in einem anderen Thread veraltet wurde.

    Jeder Thread, der auf ein flüchtiges Feld zugreift, liest seinen aktuellen Wert, bevor er fortfährt, anstatt (möglicherweise) einen zwischengespeicherten Wert zu verwenden.

    Nur Elementvariable kann flüchtig oder vorübergehend sein.

    Es gibt zwei verschiedene Verwendungszwecke für flüchtige Schlüsselwörter.

    1. Verhindert, dass JVM Werte aus dem Register liest (als Cache akzeptiert) und den Wert aus dem Speicher liest.
    2. Reduziert das Risiko von Speicherinkonsistenzerrorsn.

    Verhindert, dass JVM Werte im Register liest, und erzwingt, dass sein Wert aus dem Speicher gelesen wird.

    Ein Besetzt-Flag wird verwendet, um zu verhindern, dass ein Thread fortgesetzt wird, während das Gerät beschäftigt ist und das Flag nicht durch eine Sperre geschützt ist:

     while (busy) { /* do something else */ } 

    Der Test-Thread wird fortgesetzt, wenn ein anderer Thread das Aktivitäts-Flag deaktiviert :

     busy = 0; 

    Da jedoch im Testthread häufig auf Busy zugegriffen wird, kann die JVM den Test optimieren, indem sie den Wert von busy in ein Register legt und dann den Inhalt des Registers testet, ohne vor jedem Test den Wert von busy im Speicher zu lesen. Der Testthread würde nie eine geänderte Aktivität sehen und der andere Thread würde nur den Wert von busy im Speicher ändern, was zu einem Deadlock führen würde. Wenn das Busy-Flag als flüchtig deklariert wird, muss der Wert vor jedem Test gelesen werden.

    Reduziert das Risiko von Speicherkonsistenzerrorsn.

    Die Verwendung von flüchtigen Variablen reduziert das Risiko von Speicherkonsistenzerrorsn , da jedes Schreiben in eine flüchtige Variable eine “Vor-Vor” -Beziehung mit nachfolgenden Lesevorgängen derselben Variablen festlegt. Dies bedeutet, dass Änderungen an einer flüchtigen Variablen immer für andere Threads sichtbar sind.

    Die Technik des Lesens, Schreibens ohne Speicherkonsistenzerrors wird als atomare Aktion bezeichnet .

    Eine atomare Aktion ist eine, die effektiv auf einmal passiert. Eine atomare Aktion kann nicht in der Mitte stehen bleiben: Entweder passiert sie vollständig oder gar nicht. Keine Nebenwirkungen einer atomaren Aktion sind sichtbar, bis die Aktion abgeschlossen ist.

    Im Folgenden sind Aktionen aufgeführt, die atomar sind:

    • Lese- und Schreibvorgänge sind für Referenzvariablen und für die meisten primitiven Variablen (alle Typen außer lang und doppelt) atomar.
    • Lesen und Schreiben sind atomar für alle Variablen, die als flüchtig deklariert sind (einschließlich langer und doppelter Variablen).

    Prost!

    Flüchtige Variablen sind eine leichte Synchronisierung. Wenn die Sichtbarkeit der neuesten Daten unter allen Threads erforderlich ist und die Atomizität beeinträchtigt werden kann, müssen in solchen Situationen flüchtige Variablen bevorzugt werden. Read on volatile Variablen geben immer den letzten Schreibvorgang zurück, der von einem Thread ausgeführt wurde, da sie weder in Registern noch in Caches zwischengespeichert werden, die andere processoren nicht sehen können. Flüchtig ist Lock-Free. Ich verwende volatile, wenn das Szenario die oben genannten Kriterien erfüllt.

    Auf der oracledokumentationsseite werden flüchtige Variablen benötigt, um Speicherkonsistenzprobleme zu beheben:

    Die Verwendung von flüchtigen Variablen reduziert das Risiko von Speicherkonsistenzerrorsn, da jedes Schreiben in eine flüchtige Variable eine Vor-Vor-Beziehung mit nachfolgenden Lesevorgängen derselben Variablen festlegt.

    Dies bedeutet, dass Änderungen an einer volatile Variablen immer für andere Threads sichtbar sind. Es bedeutet auch, dass wenn ein Thread eine flüchtige Variable liest, er nicht nur die letzte Änderung der volatile , sondern auch die Nebenwirkungen des Codes sieht, der zu der Änderung geführt hat.

    Wie in der Antwort von Peter Parker erläutert, kann in Abwesenheit eines volatile Modifizierers jeder Stapel eines Threads eine eigene Kopie der Variablen haben. Indem die Variable als volatile , wurden Speicherkonsistenzprobleme behoben.

    Werfen Sie einen Blick auf die jenkov Tutorial-Seite zum besseren Verständnis.

    Sehen Sie sich die zugehörige SE-Frage an, um weitere Informationen zu flüchtigen und Anwendungsfällen zu erhalten, die flüchtig sind:

    Unterschied zwischen Volatilität und Synchronisation in Java

    Ein praktischer Anwendungsfall:

    Sie haben viele Threads, die die aktuelle Zeit in einem bestimmten Format java.text.SimpleDateFormat("HH-mm-ss") müssen, zum Beispiel: java.text.SimpleDateFormat("HH-mm-ss") . Yon kann eine class haben, die die aktuelle Zeit in SimpleDateFormat und die Variable für jede Sekunde aktualisiert. Alle anderen Threads können diese flüchtige Variable einfach verwenden, um die aktuelle Zeit in Protokolldateien zu drucken.

    Der flüchtige Schlüssel, wenn er mit einer Variablen verwendet wird, stellt sicher, dass Threads, die diese Variable lesen, denselben Wert sehen. Wenn Sie jetzt mehrere Threads lesen und in eine Variable schreiben, wird die Variable volatile nicht ausreichen und die Daten werden beschädigt. Image-Threads haben den gleichen Wert gelesen, aber jeder hat einige Chages ausgeführt (z. B. einen Zähler inkrementiert). Beim Zurückschreiben in den Speicher wird die Datenintegrität verletzt. Deshalb ist es notwendig, die Variable synchron zu machen (verschiedene Wege sind möglich)

    Wenn die Änderungen von einem Thread ausgeführt werden und die anderen nur diesen Wert lesen müssen, ist der flüchtige Wert geeignet.

    Flüchtiges folgt.

    1> Das Lesen und Schreiben flüchtiger Variablen durch verschiedene Threads erfolgt immer aus dem Speicher, nicht aus dem Thread eigenen Cache oder CPU-Register. So behandelt jeder Thread immer den neuesten Wert. 2> Wenn zwei verschiedene Threads mit derselben Instanz oder statischen Variablen im Heap arbeiten, kann es vorkommen, dass die Aktionen anderer nicht ordnungsgemäß funktionieren. Siehe dazu Jeremy Mansons Blog. Aber volatile hilft hier.

    Wenn Sie den Code vollständig ausführen, wird angezeigt, wie mehrere Threads in einer vordefinierten Reihenfolge ausgeführt und Ausgaben ausgegeben werden können, ohne ein synchronisiertes Schlüsselwort zu verwenden.

     thread 0 prints 0 thread 1 prints 1 thread 2 prints 2 thread 3 prints 3 thread 0 prints 0 thread 1 prints 1 thread 2 prints 2 thread 3 prints 3 thread 0 prints 0 thread 1 prints 1 thread 2 prints 2 thread 3 prints 3 

    Um dies zu erreichen, können wir den folgenden vollwertigen Code benutzen.

     public class Solution { static volatile int counter = 0; static int print = 0; public static void main(String[] args) { // TODO Auto-generated method stub Thread[] ths = new Thread[4]; for (int i = 0; i < ths.length; i++) { ths[i] = new Thread(new MyRunnable(i, ths.length)); ths[i].start(); } } static class MyRunnable implements Runnable { final int thID; final int total; public MyRunnable(int id, int total) { thID = id; this.total = total; } @Override public void run() { // TODO Auto-generated method stub while (true) { if (thID == counter) { System.out.println("thread " + thID + " prints " + print); print++; if (print == total) print = 0; counter++; if (counter == total) counter = 0; } else { try { Thread.sleep(30); } catch (InterruptedException e) { // log it } } } } } } 

    Der folgende GitHub-Link hat eine Readme, die eine korrekte Erklärung gibt. https://github.com/sankar4git/volatile_thread_ordering

    Ich mag die Erklärung des Jenkov

    Das flüchtige Java-Schlüsselwort wird verwendet, um eine Java-Variable als “im Hauptspeicher gespeichert” zu markieren. Genauer gesagt bedeutet dies, dass jedes Lesen einer flüchtigen Variablen aus dem Hauptspeicher des Computers und nicht aus dem CPU-Cache gelesen wird und dass jedes Schreiben in eine flüchtige Variable in den Hauptspeicher und nicht nur in den CPU-Cache geschrieben wird .

    Tatsächlich garantiert das flüchtige Schlüsselwort seit Java 5 mehr als nur, dass flüchtige Variablen in den Hauptspeicher geschrieben und daraus gelesen werden. Es ist eine erweiterte Sichtbarkeit Garantie so genannte passiert-vor-Garantie.

    Performance-Überlegungen zu volatilen

    Das Lesen und Schreiben von flüchtigen Variablen bewirkt, dass die Variable in den Hauptspeicher gelesen oder geschrieben wird. Das Lesen von und Schreiben in den Hauptspeicher ist teurer als der Zugriff auf den CPU-Cache. Der Zugriff auf flüchtige Variablen verhindert auch das Umordnen von Befehlen, was eine normale performancesverbesserungstechnik ist. Daher sollten Sie nur flüchtige Variablen verwenden, wenn Sie die Sichtbarkeit von Variablen wirklich erzwingen müssen.

    Eine flüchtige Variable wird asynchron durch gleichzeitige Ausführung von Threads in einer Java-Anwendung geändert. Es ist nicht erlaubt, eine lokale Kopie einer Variablen zu haben, die sich von dem Wert unterscheidet, der gegenwärtig im Hauptspeicher gehalten wird. Effektiv muss eine Variable, die als volatil deklariert ist, ihre Daten über alle Threads hinweg synchronisieren, so dass bei jedem Zugriff auf oder Aktualisierung der Variablen in einem Thread alle anderen Threads sofort denselben Wert sehen. Natürlich ist es wahrscheinlich, dass volatile Variablen einen höheren Zugriffs- und Update-Overhead haben als “normale” Variablen, da die Threads ihre eigene Kopie von Daten haben können, um eine bessere Effizienz zu erreichen.

    Wenn ein Feld als flüchtig deklariert wird, wird dem Compiler und der Laufzeit mitgeteilt, dass diese Variable gemeinsam genutzt wird und dass Operationen nicht mit anderen Speicheroperationen neu angeordnet werden sollen. Volitile Variablen werden nicht in Registern oder in Caches zwischengespeichert, in denen sie versteckt sind processoren, so dass ein Lesen einer flüchtigen Variablen immer den letzten Schrei von einem beliebigen Thread zurückgibt.

    Als Referenz siehe http://techno-terminal.blogspot.in/2015/11/what-are-volatile-variables.html