volatile
hat Semantik für die Sichtbarkeit des Speichers. Grundsätzlich wird der Wert eines volatile
Feldes für alle Leser sichtbar (insbesondere für andere Threads), nachdem ein Schreibvorgang abgeschlossen wurde. Ohne volatile
könnten die 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 dies der Fall ist true
. Die Bedingung kann false
durch Aufrufen einer "Stop" -Methode festgelegt werden. Die Schleife sieht false
und endet, wenn sie den Wert testet, nachdem die Stoppmethode die Ausführung abgeschlossen hat.
Das Buch " Java Concurrency in Practice ", das ich sehr empfehlen kann, gibt eine gute Erklärung dafür volatile
. Dieses Buch wurde von derselben Person verfasst, die den IBM-Artikel geschrieben hat, auf den in der Frage verwiesen wird (tatsächlich zitiert er sein Buch am Ende dieses Artikels). Ich verwende volatile
das, was sein Artikel als "Muster-1-Statusflag" bezeichnet.
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 möchten, lesen Sie ein gutes Buch zur Computerarchitektur wie Hennessy & Patterson und lesen Sie mehr über Cache-Kohärenz und Cache-Konsistenz.
volatile
, die mit dem in JSR 133 definierten neuen Java-Speichermodell verbunden ist, wird weggelassen: Wenn ein Thread einevolatile
Variable liest , sieht er nicht nur den Wert, der zuletzt von einem anderen Thread in ihn geschrieben wurde, sondern auch alle anderen Schreibvorgänge in andere Variablen, die waren zum Zeitpunkt desvolatile
Schreibens in diesem anderen Thread sichtbar . Siehe diese Antwort und diese Referenz ."... der flüchtige Modifikator garantiert, dass jeder Thread, der ein Feld liest, den zuletzt geschriebenen Wert sieht." - Josh Bloch
Wenn Sie über die Verwendung nachdenken
volatile
, lesen Sie das Paket,java.util.concurrent
das sich mit atomarem Verhalten befasst.Der Wikipedia-Beitrag zu einem Singleton-Muster zeigt eine flüchtige Verwendung.
quelle
volatile
undsynchronized
Schlüsselwörter?volatile
Beispiel nicht mehr. Es kann in einer archivierten Version gefunden werden .void
undpublic
Schlüsselwörter".Wichtiger Punkt zu
volatile
:synchronized
undvolatile
und Schlösser.synchronized
Variablen haben. Die Verwendung einessynchronized
Schlüsselworts mit einer Variablen ist unzulässig und führt zu einem Kompilierungsfehler. Anstatt diesynchronized
Variable in Java zu verwenden, können Sie auch die Java-volatile
Variable verwenden, die JVM-Threads anweist, den Wert dervolatile
Variablen aus dem Hauptspeicher zu lesen und nicht lokal zwischenzuspeichern.volatile
Schlüsselwort nicht verwendet werden.Quelle
Beispiel für die Verwendung von
volatile
:Wir erstellen die Instanz träge zum Zeitpunkt der ersten Anfrage.
Wenn wir die
_instance
Variable nichtvolatile
erstellen, kann der Thread, der die Instanz von erstellt,Singleton
nicht mit dem anderen Thread kommunizieren. Wenn Thread A eine Singleton-Instanz erstellt und die CPU unmittelbar nach der Erstellung beschädigt wird, können alle anderen Threads den Wert von_instance
nicht als null anzeigen und glauben, dass ihm immer noch null zugewiesen ist.Warum passiert das? Da Reader-Threads nicht gesperrt werden und der Writer-Thread erst aus einem synchronisierten Block herauskommt, wird der Speicher nicht synchronisiert und der Wert von
_instance
wird im Hauptspeicher nicht aktualisiert. Mit dem Schlüsselwort Volatile in Java wird dies von Java selbst behandelt, und solche Aktualisierungen sind für alle Reader-Threads sichtbar.Beispiel Verwendung von ohne flüchtig:
Der obige Code ist nicht threadsicher. Obwohl der Wert der Instanz innerhalb des synchronisierten Blocks (aus Leistungsgründen) erneut überprüft wird, kann der JIT-Compiler den Bytecode so neu anordnen, dass der Verweis auf die Instanz festgelegt 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 das Schlüsselwort volatile seit Java 5 für die Instanzvariable verwendet werden. Variablen, die als flüchtig markiert sind, werden für andere Threads erst sichtbar, wenn der Konstruktor des Objekts seine Ausführung vollständig abgeschlossen hat.
Quelle
volatile
Verwendung in Java :Die ausfallsicheren Iteratoren werden normalerweise mithilfe eines
volatile
Zählers für das Listenobjekt implementiert .Iterator
erstellt wird, wird der aktuelle Wert des Zählers in dasIterator
Objekt eingebettet .Iterator
Operation ausgeführt wird, vergleicht die Methode die beiden Zählerwerte und löst a aus,ConcurrentModificationException
wenn sie unterschiedlich sind.Die Implementierung von ausfallsicheren Iteratoren ist normalerweise leicht. Sie stützen sich normalerweise auf Eigenschaften der Datenstrukturen der spezifischen Listenimplementierung. Es gibt kein allgemeines Muster.
quelle
private static final Singleton _instance;
.volatile
ist sehr nützlich, um Threads zu stoppen.Nicht, dass Sie Ihre eigenen Threads schreiben sollten, Java 1.6 hat viele nette Thread-Pools. Wenn Sie jedoch 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:
Im obigen Codesegment unterscheidet sich das Lesen des Threads
close
in der while-Schleife von dem, der aufgerufen wirdclose()
. Ohne flüchtig kann der Thread, der die Schleife ausführt, die Änderung möglicherweise nie schließen.Beachten Sie, dass keine Synchronisierung erforderlich ist
quelle
volatile
Schlüsselwort, und es scheint immer gut zu funktionieren.Ein häufiges Beispiel für die Verwendung
volatile
ist die Verwendung einervolatile boolean
Variablen als Flag zum Beenden eines Threads. Wenn Sie einen Thread gestartet haben und ihn sicher von einem anderen Thread aus unterbrechen möchten, können Sie den Thread regelmäßig ein Flag überprüfen lassen. Um es zu stoppen, setzen Sie das Flag auf true. Indem Sie das Flag setzenvolatile
, können Sie sicherstellen, dass der Thread, der es überprüft, sieht, dass es beim nächsten Überprüfen gesetzt wurde, ohne einensynchronized
Block verwenden zu müssen.quelle
Eine mit
volatile
Schlüsselwort deklarierte Variable hat zwei Hauptqualitäten, die sie zu etwas Besonderem machen.Wenn wir eine flüchtige Variable haben, kann sie von keinem Thread im Cache-Speicher des Computers (Mikroprozessor) zwischengespeichert werden. Der Zugriff erfolgte immer aus dem Hauptspeicher.
Wenn eine Schreiboperation für eine flüchtige Variable ausgeführt wird und plötzlich eine Leseoperation angefordert wird, wird garantiert, dass die Schreiboperation vor der Leseoperation beendet wird .
Zwei oben genannte Eigenschaften leiten das ab
Und auf der anderen Seite,
volatile
Schlüsselwort ein idealer Weg ist, um eine gemeinsam genutzte Variable zu verwalten, die 'n' Anzahl von Reader-Threads und nur einen Writer-Thread hat, um darauf zuzugreifen. Sobald wir dasvolatile
Schlüsselwort hinzugefügt haben , ist es fertig. Kein weiterer Aufwand für die Gewindesicherheit.Umgekehrt,
Wir können das
volatile
Schlüsselwort nicht nur verwenden, um eine gemeinsam genutzte Variable zu erfüllen, auf die mehr als ein Writer-Thread zugreift .quelle
Niemand hat die Behandlung der Lese- und Schreiboperation für lange und doppelte variable Typen erwähnt. Lese- und Schreibvorgänge sind atomare Operationen für Referenzvariablen und für die meisten primitiven Variablen, mit Ausnahme von langen und doppelten Variablentypen, bei denen das Schlüsselwort volatile verwendet werden muss, um atomare Operationen zu sein. @Verknüpfung
quelle
Ja, flüchtig muss immer dann verwendet werden, wenn mehrere Threads auf eine veränderbare Variable zugreifen möchten. Dies ist nicht sehr häufig der Fall, da Sie normalerweise mehr als eine einzelne atomare Operation ausführen müssen (z. B. den Variablenstatus überprüfen, bevor Sie ihn ändern). In diesem Fall würden Sie stattdessen einen synchronisierten Block verwenden.
quelle
Meiner Meinung nach sind zwei wichtige Szenarien außer dem Stoppen des Threads, in dem das flüchtige Schlüsselwort verwendet wird, folgende:
quelle
Sie müssen das Schlüsselwort 'volatile' oder 'synchronized' und alle anderen Tools und Techniken zur Parallelitätskontrolle verwenden, die Ihnen möglicherweise 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 dem Anwendungsserver (Tomcat, JBoss AS, Glassfish usw.) bereitgestellt wird, müssen Sie die Parallelitätskontrolle nicht selbst durchführen, da sie bereits vom Anwendungsserver adressiert wird. Wenn ich mich richtig erinnere, verbietet der Java EE-Standard jegliche Parallelitätskontrolle in Servlets und EJBs, da er Teil der Infrastrukturschicht ist, von der Sie angenommen haben, dass sie nicht mehr damit umgehen kann. Sie führen in einer solchen App nur eine Parallelitätskontrolle durch, wenn Sie Singleton-Objekte implementieren. Dies wurde sogar bereits behoben, wenn Sie Ihre Komponenten mit Frameworkd wie Spring stricken.
In den meisten Fällen der Java-Entwicklung, in denen die Anwendung eine Webanwendung ist und ein IoC-Framework wie Spring oder EJB verwendet, müssen Sie "volatile" nicht verwenden.
quelle
volatile
garantiert nur, dass alle Threads, auch sie selbst, inkrementiert werden. Beispiel: Ein Zähler sieht zur gleichen Zeit dasselbe Gesicht der Variablen. Es wird nicht anstelle von synchronisiertem oder atomarem oder anderem Material verwendet, sondern macht die Lesevorgänge vollständig synchronisiert. Bitte vergleichen Sie es nicht mit anderen Java-Schlüsselwörtern. Wie das folgende Beispiel zeigt, sind flüchtige variable Operationen ebenfalls atomar, sie schlagen fehl oder sind sofort erfolgreich.Selbst wenn Sie volatile oder nicht volatile Ergebnisse erzielen, werden diese immer unterschiedlich ausfallen. Wenn Sie jedoch AtomicInteger wie folgt verwenden, sind die Ergebnisse immer gleich. Dies gilt auch für synchronisierte.
quelle
Ja, ich benutze es ziemlich oft - es kann sehr nützlich für Multithread-Code sein. Der Artikel, auf den Sie hingewiesen haben, ist gut. Es gibt jedoch zwei wichtige Dinge zu beachten:
quelle
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 die Mitgliedsvariable kann flüchtig oder vorübergehend sein.
quelle
Absolut ja. (Und das nicht nur in Java, sondern auch in C #.) Es gibt Zeiten, in denen Sie einen Wert abrufen oder festlegen müssen, der garantiert eine atomare Operation auf Ihrer bestimmten Plattform ist, z. B. ein int oder ein boolescher Wert, aber nicht erforderlich der Overhead der Thread-Verriegelung. Mit dem Schlüsselwort volatile können Sie sicherstellen, dass Sie beim Lesen des Werts den aktuellen Wert erhalten und keinen zwischengespeicherten Wert, der gerade durch ein Schreiben in einen anderen Thread veraltet wurde.
quelle
Es gibt zwei verschiedene Verwendungen von flüchtigen Schlüsselwörtern.
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:
Der Test-Thread wird fortgesetzt, wenn ein anderer Thread das Besetzt-Flag ausschaltet :
Da jedoch im Testthread häufig auf Besetzt zugegriffen wird, kann die JVM den Test optimieren, indem sie den Wert von Besetzt in ein Register legt und dann den Inhalt des Registers testet, ohne den Wert von Besetzt im Speicher vor jedem Test zu lesen. Der Test-Thread würde niemals eine Besetzt-Änderung sehen und der andere Thread würde nur den Wert von Besetzt im Speicher ändern, was zu einem Deadlock führen würde. Wenn Sie das Besetzt-Flag als flüchtig deklarieren, wird sein Wert vor jedem Test gelesen.
Die Verwendung flüchtiger Variablen verringert das Risiko von Speicherkonsistenzfehlern , da beim Schreiben in eine flüchtige Variable eine "Vorher-passiert" -Beziehung mit nachfolgenden Lesevorgängen derselben Variablen hergestellt wird. Dies bedeutet, dass Änderungen an einer flüchtigen Variablen für andere Threads immer sichtbar sind.
Die Technik des Lesens und Schreibens ohne Speicherkonsistenzfehler wird als atomare Aktion bezeichnet .
Eine atomare Aktion ist eine, die effektiv auf einmal stattfindet. Eine atomare Aktion kann nicht in der Mitte aufhören: Sie geschieht entweder vollständig oder überhaupt nicht. Bis zum Abschluss der Aktion sind keine Nebenwirkungen einer atomaren Aktion sichtbar.
Im Folgenden finden Sie Aktionen, die Sie angeben können und die atomar sind:
Prost!
quelle
Volatile macht folgendes.
1> Das Lesen und Schreiben flüchtiger Variablen durch verschiedene Threads erfolgt immer aus dem Speicher, nicht aus dem eigenen Cache oder CPU-Register des Threads. Jeder Thread befasst sich also immer mit dem neuesten Wert. 2> Wenn zwei verschiedene Threads mit derselben Instanz oder statischen Variablen im Heap arbeiten, werden die Aktionen anderer möglicherweise als nicht in Ordnung angesehen. Siehe dazu Jeremy Mansons Blog. Aber flüchtig hilft hier.
Der folgende vollständig ausgeführte Code zeigt, wie eine Reihe von Threads in vordefinierter Reihenfolge ausgeführt und Ausgaben ohne Verwendung eines synchronisierten Schlüsselworts gedruckt werden können.
Um dies zu erreichen, können wir den folgenden vollwertigen laufenden Code verwenden.
Der folgende Github-Link enthält eine Readme-Datei, die eine angemessene Erklärung enthält. https://github.com/sankar4git/volatile_thread_ordering
quelle
volatile
sagt für einen Programmierer, dass der Wert immer aktuell sein wird. Das Problem ist, dass der Wert auf verschiedenen Arten von Hardwarespeicher gespeichert werden kann. Zum Beispiel können es CPU-Register, CPU-Cache, RAM ... sein. UPU-Register und CPU-Cache gehören zur CPU und können im Gegensatz zu RAM, das in der Multithreading-Umgebung auf der Rettung ist, keine Daten gemeinsam nutzenvolatile
Das Schlüsselwort besagt, dass eine Variable direkt aus dem / in den RAM-Speicher gelesen und geschrieben wird . Es hat einen gewissen RechenaufwandJava 5
erweitertvolatile
durch die Unterstützung vonhappens-before
[About]volatile
Stichwort nicht heilen einerace condition
Situation , wenn mehrere Threads können schreiben gleichzeitig einige Werte. Die Antwort lautetsynchronized
Schlüsselwort [Info]Infolgedessen ist es nur dann sicher , wenn ein Thread schreibt und andere nur den
volatile
Wert lesenflüchtig vs synchronisiert
quelle
Von der Oracle - Dokumentation Seite ergibt sich die Notwendigkeit für flüchtigen Variable fix Speicherkonsistenzprobleme:
Dies bedeutet, dass Änderungen an einer
volatile
Variablen für andere Threads immer sichtbar sind. Dies bedeutet auch, dass ein Thread beim Lesen einer flüchtigen Variablen nicht nur die letzte Änderung an dervolatile
, sondern auch die Nebenwirkungen des Codes sieht , der die Änderung ausgelöst hat.Wie in der
Peter Parker
Antwort erläutert ,volatile
kann der Stapel jedes Threads ohne Modifikator eine eigene Kopie der Variablen haben. Durch das Festlegen der Variablen alsvolatile
wurden Speicherkonsistenzprobleme behoben.Schauen Sie sich zum besseren Verständnis die jenkov- Tutorial-Seite an.
In der zugehörigen SE-Frage finden Sie weitere Informationen zu flüchtigen und Anwendungsfällen für die Verwendung von flüchtigen Stoffen:
Unterschied zwischen flüchtig und synchronisiert in Java
Ein praktischer Anwendungsfall:
Sie haben viele Threads, die die aktuelle Zeit in einem bestimmten Format drucken müssen, zum Beispiel :
java.text.SimpleDateFormat("HH-mm-ss")
. Sie können eine Klasse haben, die die aktuelle Zeit in eineSimpleDateFormat
Variable umwandelt und diese für jede Sekunde aktualisiert. Alle anderen Threads können diese flüchtige Variable einfach verwenden, um die aktuelle Zeit in Protokolldateien zu drucken.quelle
Flüchtige Variablen sind leichte Synchronisation. Wenn die Sichtbarkeit der neuesten Daten für alle Threads erforderlich ist und die Atomizität beeinträchtigt werden kann, müssen in solchen Situationen flüchtige Variablen bevorzugt werden. Beim Lesen von flüchtigen Variablen wird immer der letzte Schreibvorgang zurückgegeben, der von einem Thread ausgeführt wurde, da sie weder in Registern noch in Caches zwischengespeichert werden, die andere Prozessoren nicht sehen können. Flüchtig ist sperrenfrei. Ich benutze volatile, wenn das Szenario die oben genannten Kriterien erfüllt.
quelle
Der flüchtige Schlüssel stellt bei Verwendung mit einer Variablen sicher, dass Threads, die diese Variable lesen, denselben Wert sehen. Wenn Sie nun mehrere Threads haben, die in eine Variable lesen und schreiben, reicht es nicht aus, die Variable flüchtig zu machen, und die Daten werden beschädigt. Bild-Threads haben den gleichen Wert gelesen, aber jeder hat einige Änderungen vorgenommen (z. B. einen Zähler erhöht). Beim Zurückschreiben in den Speicher wird die Datenintegrität verletzt. Aus diesem Grund muss die Variable synchronisiert werden (verschiedene Möglichkeiten sind möglich).
Wenn die Änderungen von einem Thread vorgenommen werden und die anderen nur diesen Wert lesen müssen, ist der flüchtige Stoff geeignet.
quelle
Die flüchtige Variable wird grundsätzlich für die sofortige Aktualisierung (Flush) in der gemeinsam genutzten Hauptcachezeile nach der Aktualisierung verwendet, sodass Änderungen sofort auf alle Arbeitsthreads übertragen werden.
quelle
Im Folgenden finden Sie einen sehr einfachen Code, der die Anforderung einer
volatile
Variablen demonstriert, mit der die Thread-Ausführung von einem anderen Thread aus gesteuert wird (dies ist ein Szenario, in dem diesvolatile
erforderlich ist).Wenn
volatile
nicht verwendet: Die Meldung " Gestoppt am: xxx " wird auch nach " Anhalten am: xxx " nie angezeigt , und das Programm wird weiterhin ausgeführt.Bei
volatile
Verwendung: Sie sehen sofort " Gestoppt am: xxx ".Demo: https://repl.it/repls/SilverAgonizingObjectcode
quelle