37 Stimmen

Schlüsselwort Volatile in Java - Klarstellung

Ich bin wirklich verwirrt über das, was ich über die Anwendungen des volatile-Schlüsselworts in Java gelesen habe.

  1. Ist die folgende Aussage korrekt? "Eine Schreiboperation auf ein volatiles Feld findet vor jedem folgenden Lesezugriff auf dasselbe Feld statt"

  2. Wann sollte idealerweise das volatile-Schlüsselwort verwendet werden?

  3. Was ist der Unterschied zwischen:

    class TestClass
    {  private int x;
    
       synchronized int get(){return x;}
       synchronized void set(int x){this.x = x;}
    
    }

und

class TestClass
{  private volatile int x;

   int get(){return x;}
   void set(int x){this.x = x;}

}

0 Stimmen

Um meinen automatischen "Möglicherweise" -Duplikatkommentar zu klären: Die beiden vorherigen Vorschläge waren keine exakten Duplikate; meiner ist es. Es ist wichtig, dass diese Frage als Duplikat geklärt wird, da die ausgewählte Antwort auf diese Frage gefährlich falsch ist, wenn sie behauptet, dass volatil nur das als volatil deklarierte Feld betrifft - tatsächlich führt ein Schreib- und ein Lesebefehl von jeder volatilen Variable eine vollständige Speicherbarriere ein, genauso wie die Synchronisation zwischen zwei Threads.

0voto

Manu Punkte 7673

Die Antwort von Kerem Baydogan ist vollkommen richtig. Ich möchte nur ein praktisches Beispiel dafür geben, was das volatile Schlüsselwort uns bietet.

Zuerst haben wir einen Zähler, so etwas wie

public class Counter {
    private int x;
    public int getX() { return x; }
    public void increment() { x++; }
}

Und einige Runnable-Aufgaben, die den Wert von x inkrementieren

@Override
public void run() {
    for (N) {
            int alterWert = counter.getX();
            counter.increment();
            int neuer Wert = counter.getX();
        }

    }
}

Ohne Synchronisierung kommt es zu Interferenzen zwischen Threads und es funktioniert einfach nicht.

Der einfachste Weg, dies zu lösen:

public class Counter {
    private int x;
    public synchronized int getX() { return x; }
    public synchronized void increment() { x++; }
}

Um das System tatsächlich zum Absturz zu bringen, führe ich ein Thread.sleep vor dem Lesen und Schreiben von x


Also, wofür ist volatile nützlich? Es gibt viele gute Artikel darüber: volatile-Artikel oder diese Frage

Die Synchronisierung des Zugriffs auf die gemeinsame Ressource ist nicht die Antwort, aber es ist eine gute Wahl, um den Flag zum Stoppen von Threads zu halten

In unserem vorherigen Beispiel, stellen wir uns vor, wir möchten die Variable bis 100 inkrementieren, eine einfache Möglichkeit könnte ein volatile boolean Flag sein. Beispiel:

private volatile boolean stop;

@Override
public void run() {
    while(!stop) {
        int alterWert = counter.getX();
        if (alterWert == 100) {
             stop = true;
        } else {
             counter.increment();
             int neuer Wert = counter.getX();
        }       
     }
}

Das funktioniert gut, aber wenn du das volatile Schlüsselwort aus dem Flag entfernst, besteht die Möglichkeit einer Endlosschleife.

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