801 Stimmen

Wofür ist das Schlüsselwort volatile nützlich?

Bei der Arbeit stieß ich heute auf die volatile Schlüsselwort in Java. Da ich damit nicht sehr vertraut bin, fand ich diese Erklärung .

Wenn man bedenkt, wie detailliert in diesem Artikel das betreffende Schlüsselwort erklärt wird, haben Sie es dann jemals verwendet oder könnten Sie sich einen Fall vorstellen, in dem Sie dieses Schlüsselwort auf die richtige Art und Weise verwenden könnten?

861voto

Greg Mattes Punkte 31690

volatile hat eine Semantik für Speichersichtbarkeit. Grundsätzlich ist der Wert einer volatile Feld wird für alle Leser (insbesondere für andere Threads) sichtbar, nachdem ein Schreibvorgang darauf abgeschlossen wurde. Ohne volatile könnten die Leser einen nicht aktualisierten Wert sehen.

Um Ihre Frage zu beantworten: Ja, ich verwende ein volatile um zu steuern, ob ein Code eine Schleife fortsetzt. Die Schleife testet die volatile Wert und fährt fort, wenn er true . Die Bedingung kann eingestellt werden auf false durch den Aufruf einer "Stop"-Methode. Die Schleife sieht false und bricht ab, wenn es den Wert nach Beendigung der Ausführung der Stop-Methode testet.

Das Buch " Java-Gleichzeitigkeit in der Praxis ", das ich sehr empfehle, gibt eine gute Erklärung der volatile . Dieses Buch wurde von der gleichen Person geschrieben, die auch den IBM-Artikel verfasst hat, auf den in der Frage Bezug genommen wird (er zitiert sein Buch sogar am Ende des Artikels). Meine Verwendung von volatile ist das, was in seinem Artikel als "Muster-1-Statusflagge" bezeichnet wird.

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

158 Stimmen

Diese Antwort ist richtig, aber unvollständig. Sie lässt eine wichtige Eigenschaft von volatile die mit dem neuen, in JSR 133 definierten Java-Speichermodell einhergeht: Wenn ein Thread eine volatile sieht sie nicht nur den Wert, der ihr zuletzt von einem anderen Thread geschrieben wurde, sondern auch alle anderen Schreibvorgänge auf andere Variablen, die in diesem anderen Thread zum Zeitpunkt des Schreibvorgangs sichtbar waren. volatile schreiben. Siehe diese Antwort y dieser Bezug .

53 Stimmen

Für Anfänger würde ich Sie bitten, dies mit etwas Code zu demonstrieren (bitte?)

8 Stimmen

Der in der Frage verlinkte Artikel enthält Codebeispiele.

217voto

Ande Turner Punkte 6828

" der flüchtige Modifikator garantiert, dass jeder Thread, der ein Feld liest, den zuletzt geschriebenen Wert sieht." - Josh Bloch

Wenn Sie darüber nachdenken, Folgendes zu verwenden volatile lesen Sie auf der Verpackung nach java.util.concurrent die sich mit atomarem Verhalten befasst.

Der Wikipedia-Beitrag über eine Singleton-Muster zeigt flüchtig im Einsatz.

23 Stimmen

Warum gibt es beides volatile y synchronized Schlüsselwörter?

7 Stimmen

Der Wikipedia-Artikel über ein Singleton-Muster hat sich inzwischen stark verändert und enthält nicht mehr den Hinweis volatile Beispiel nicht mehr. Es kann gefunden werden in einer archivierten Version .

4 Stimmen

@ptkato Diese beiden Schlüsselwörter dienen völlig unterschiedlichen Zwecken, so dass die Frage als Vergleich nicht viel Sinn macht, obwohl sie beide mit Gleichzeitigkeit zu tun haben. Es ist, als würde man sagen: "Warum gibt es beide void y public Schlüsselwörter".

189voto

Premraj Punkte 65511

Flüchtig (vltl): Leicht verdunstend bei normalen Temperaturen

Wichtiger Punkt über volatile :

  1. Die Synchronisierung in Java ist durch die Verwendung von Java-Schlüsselwörtern möglich synchronized et volatile und Schlösser.
  2. In Java können wir nicht haben synchronized variabel. Verwendung von synchronized Schlüsselwort mit einer Variablen ist illegal und führt zu einem Kompilierungsfehler. Anstelle der Verwendung des synchronized Variable in Java zu verwenden, können Sie die java volatile Variable, die JVM-Threads anweist, den Wert von volatile Variable aus dem Hauptspeicher und speichern Sie sie nicht lokal zwischen.
  3. Wenn eine Variable nicht von mehreren Threads gemeinsam genutzt wird, ist es nicht notwendig, die volatile Stichwort.

Quelle

Beispiel für die 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 die Instanz erst dann, wenn die erste Anfrage kommt.

Wenn wir nicht die _instance variabel volatile dann wird der Thread, der die Instanz von Singleton ist nicht in der Lage, mit dem anderen Thread zu kommunizieren. Wenn also Thread A eine Singleton-Instanz erstellt und kurz nach der Erstellung die CPU beschädigt wird usw., können alle anderen Threads den Wert von _instance als nicht null, und sie werden glauben, dass es immer noch als null zugewiesen wird.

Warum ist das so? Weil Leser-Threads nicht sperren und bis der Schreiber-Thread aus einem synchronisierten Block herauskommt, wird der Speicher nicht synchronisiert und der Wert von _instance wird nicht im Hauptspeicher aktualisiert. Mit dem Schlüsselwort Volatile in Java wird dies von Java selbst gehandhabt, und solche Aktualisierungen sind für alle Leser-Threads sichtbar.

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

Beispiel für die Verwendung von ohne flüchtig:

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 er den Wert der Instanz innerhalb des synchronisierten Blocks noch einmal überprüft (aus Leistungsgründen), kann der JIT-Compiler den Bytecode so umstellen, dass der Verweis auf die Instanz gesetzt wird, bevor der Konstruktor seine Ausführung beendet hat. Das bedeutet, dass die Methode getInstance() ein Objekt zurückgibt, das möglicherweise nicht vollständig initialisiert wurde. Um den Code thread-sicher zu machen, kann seit Java 5 das Schlüsselwort volatile für die Instanzvariable verwendet werden. Variablen, die als flüchtig gekennzeichnet sind, werden für andere Threads erst sichtbar, wenn der Konstruktor des Objekts seine Ausführung vollständig beendet hat.
Quelle

enter image description here

volatile Verwendung in Java :

Die ausfallsicheren Iteratoren sind typischerweise implementiert mit einer volatile Zähler auf dem Listenobjekt.

  • Wenn die Liste aktualisiert wird, wird der Zähler erhöht.
  • Wenn ein Iterator erstellt wird, wird der aktuelle Wert des Zählers in die Iterator Objekt.
  • Wenn ein Iterator Operation durchgeführt wird, vergleicht die Methode die beiden Zählerwerte und löst einen ConcurrentModificationException wenn sie unterschiedlich sind.

Die Implementierung von ausfallsicheren Iteratoren ist in der Regel leichtgewichtig. Sie beruhen in der Regel auf den Eigenschaften der Datenstrukturen der jeweiligen Listenimplementierung. Es gibt kein allgemeines Muster.

2 Stimmen

"Die ausfallsicheren Iteratoren werden typischerweise mit einem flüchtigen Zähler implementiert" - nicht mehr der Fall, zu kostspielig: bugs.java.com/bugdatabase/view_bug.do?bug_id=6625725

0 Stimmen

Sind die doppelte Überprüfung für _instance sicher? ich dachte, sie sind nicht sicher, auch mit flüchtigen

1 Stimmen

"was die JVM-Threads anweist, den Wert der flüchtigen Variablen aus dem Hauptspeicher zu lesen und nicht lokal zwischenzuspeichern" - guter Punkt

67voto

Pyrolistical Punkte 26854

volatile ist sehr nützlich, um Threads anzuhalten.

Nicht, dass Sie Ihre eigenen Threads schreiben sollten, Java 1.6 hat eine Menge schöner Thread-Pools. Aber wenn Sie sicher sind, dass Sie einen Thread brauchen, müssen Sie wissen, wie Sie ihn anhalten können.

Das Muster, das ich für die Fäden verwende, lautet:

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
  }
}

In dem obigen Codesegment liest der Thread close in der while-Schleife unterscheidet sich von derjenigen, die close() . Ohne Volatile sieht der Thread, der die Schleife ausführt, möglicherweise nie die Änderung zum Schließen.

Beachten Sie, dass eine Synchronisierung nicht erforderlich ist.

2 Stimmen

Ich frage mich, warum das überhaupt notwendig ist. Ist das nicht nur notwendig, wenn andere Threads auf die Statusänderung dieses Threads so reagieren müssen, dass die Synchronisation des Threads in Gefahr ist?

34 Stimmen

@Jori, Sie brauchen volatile, weil der Thread, der close in der while-Schleife liest, ein anderer ist als derjenige, der close() aufruft. Ohne volatile sieht der Thread, der die Schleife ausführt, möglicherweise nie die Änderung in close.

1 Stimmen

Würden Sie sagen, es gibt einen Vorteil zwischen Anhalten eines Threads wie das oder mit Thread#interrupt() und Thread#isInterrupted() Methoden?

44voto

Supun Wijerathne Punkte 10926

Eine Variable, die mit volatile hat zwei wesentliche Eigenschaften, die es zu etwas Besonderem machen.

  1. Wenn wir eine flüchtige Variable haben, kann sie von keinem Thread im Cache-Speicher des Computers (Mikroprozessors) zwischengespeichert werden. Der Zugriff erfolgt immer vom Hauptspeicher aus.

  2. Wenn es eine Schreibvorgang auf eine flüchtige Variable, und plötzlich wird eine Lesevorgang angefordert wird, ist gewährleistet, dass die der Schreibvorgang wird vor dem Lesevorgang abgeschlossen .

Aus den beiden oben genannten Eigenschaften ergibt sich, dass

  • Alle Threads, die eine flüchtige Variable lesen, werden definitiv den letzten Wert lesen. Denn kein zwischengespeicherter Wert kann ihn verunreinigen. Und auch die Leseanforderung wird erst nach Abschluss des aktuellen Schreibvorgangs gewährt.

Und auf der anderen Seite,

  • Wenn wir das Thema weiter untersuchen #2 die ich erwähnt habe, können wir sehen, dass volatile ist ein idealer Weg, um eine gemeinsame Variable zu pflegen, die 'n' Anzahl von Leser-Threads und nur ein Schreiber-Thread um darauf zuzugreifen. Sobald wir die volatile Schlüsselwort, ist es erledigt. Kein weiterer Overhead über die Threadsicherheit.

Konversation,

Wir kann nicht ausnutzen volatile Schlüsselwort, um eine gemeinsame Variable zu erfüllen, die mehr als ein Writer-Thread darauf zugreift .

4 Stimmen

Dies erklärt den Unterschied zwischen flüchtig und synchronisiert.

3 Stimmen

Das ist leider falsch. "Volatile" kontrolliert nicht den Cache und bietet keine magische sofortige globale Aktualisierung für Speicheransichten anderer CPUs. "Volatile" stellt lediglich sicher, dass die JVM bei jedem Verweis auf die Variable (entweder lesend oder schreibend) einen Verweis auf die zugewiesene Adresse der Variablen im virtuellen Speicher ausführt und nicht auf einen Wert, der in einem Register oder an einem anderen vom Optimierer ausgewählten, bequemen Schattenspeicherplatz (z. B. Stack) gespeichert ist, und auch keinen Verweis nach dem Ermessen des Optimierers überspringt.

3 Stimmen

Ohne "volatile" würde eine Anweisung wie "for (...) {a += b + c;}" möglicherweise überhaupt nicht auf Speicherplätze verweisen, sondern lediglich "a", "b" und "c" während der gesamten Dauer der Schleife in Registern halten. Wenn ein Wert von der CPU in eine virtuelle Speicheradresse (oder eine entsprechende physische Speicheradresse) geschrieben wird, ist die Aktualisierung weder sofort für andere CPUs sichtbar, noch wird sie sofort in den Arbeitsspeicher übertragen [*].

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X