it-swarm.com.de

Volatile vs Static in Java

Ist es richtig zu sagen, dass static eine Kopie des Wertes für alle Objekte und volatile eine Kopie des Wertes für alle Threads bedeutet?

Wie auch immer, ein static Variablenwert wird auch ein Wert für alle Threads sein. Warum sollten wir dann volatile wählen?

255
Jothi

Das Deklarieren einer statischen Variablen in Java bedeutet, dass nur eine Kopie vorhanden ist, unabhängig davon, wie viele Objekte der Klasse erstellt werden. Auf die Variable kann auch dann zugegriffen werden, wenn überhaupt kein Objects erstellt wurde. Threads können jedoch lokal zwischengespeicherte Werte haben.

Wenn eine Variable flüchtig und nicht statisch ist, gibt es eine Variable für jedes Object. An der Oberfläche scheint es also keinen Unterschied zu einer normalen Variablen zu geben, sondern einen Unterschied zu static . Selbst mit Object -Feldern kann ein Thread einen Variablenwert lokal zwischenspeichern.

Das heißt, wenn zwei Threads gleichzeitig eine Variable desselben Objekts aktualisieren und die Variable nicht als flüchtig deklariert wird, kann es vorkommen, dass einer der Threads einen alten Wert im Cache hat.

Selbst wenn Sie über mehrere Threads auf einen statischen Wert zugreifen, kann für jeden Thread eine lokal zwischengespeicherte Kopie vorhanden sein! Um dies zu vermeiden, können Sie die Variable als static volatile deklarieren. Dadurch wird der Thread jedes Mal gezwungen, den globalen Wert zu lesen.

volatile ist jedoch kein Ersatz für eine ordnungsgemäße Synchronisation!
Zum Beispiel:

private static volatile int counter = 0;

private void concurrentMethodWrong() {
  counter = counter + 5;
  //do something
  counter = counter - 5;
}

Das mehrmalige Ausführen von concurrentMethodWrong kann zu einem von Null verschiedenen Endwert des Zählers führen!
Um das Problem zu lösen, müssen Sie eine Sperre implementieren:

private static final Object counterLock = new Object();

private static volatile int counter = 0;

private void concurrentMethodRight() {
  synchronized (counterLock) {
    counter = counter + 5;
  }
  //do something
  synchronized (counterLock) {
    counter = counter - 5;
  }
}

Oder verwenden Sie die Klasse AtomicInteger .

351
stivlo

Unterschied zwischen statisch und flüchtig:

Statische Variable: Wenn zwei Threads (angenommen t1 und t2) greifen auf dasselbe Objekt zu und aktualisieren eine Variable, die als statisch deklariert ist, dann bedeutet dies t1 und t2 kann eine eigene lokale Kopie desselben Objekts (einschließlich statischer Variablen) in ihrem jeweiligen Cache erstellen. Die Aktualisierung erfolgt also durch t1 für die statische Variable in ihrem lokalen Cache spiegelt sich nicht in der statischen Variablen für t2 Zwischenspeicher .

Statische Variablen werden im Kontext von Object verwendet, wobei die Aktualisierung, die von einem Objekt vorgenommen wird, in allen anderen Objekten derselben Klasse wiedergegeben wird jedoch nicht im Kontext von Thread wobei die Aktualisierung von Ein Thread für die statische Variable spiegelt die Änderungen sofort für alle Threads (in ihrem lokalen Cache) wider.

Flüchtige Variable: Wenn zwei Threads (angenommen t1 und t2) greifen auf dasselbe Objekt zu und aktualisieren eine Variable, die als flüchtig deklariert ist, dann bedeutet dies t1 und t2 kann einen eigenen lokalen Cache des Objekts erstellen mit Ausnahme der als flüchtig deklarierten Variablen. Die flüchtige Variable hat also nur eine Hauptkopie, die von verschiedenen Threads aktualisiert wird, und die Aktualisierung, die ein Thread für die flüchtige Variable vornimmt, wird sofort für den anderen Thread übernommen.

283
Som

Zusätzlich zu anderen Antworten möchte ich ein Bild hinzufügen (Bild macht leicht verständlich)

enter image description here

static Variablen können für einzelne Threads zwischengespeichert werden. In einer Umgebung mit mehreren Threads werden die zwischengespeicherten Daten eines Threads möglicherweise nicht für andere Threads übernommen, da eine Kopie vorhanden ist.

Die volatile -Deklaration stellt sicher, dass Threads die Daten nicht zwischenspeichern und verwendet nur die gemeinsam genutzte Kopie .

Bildquelle

26
mrsrinivas

Ich denke, static und volatile haben überhaupt keine Beziehung. Ich schlage vor, Sie lesen Java Tutorial zu verstehen Atomic Access , und warum Atomic Access verwenden, verstehen, was Interleaved ist, werden Sie Antwort finden.

5
Amitābha

In einfachen Worten,

  1. statisch : static Variablen werden eher mit class verknüpft als bei jedem Objekt. Jede Instanz der Klasse hat eine gemeinsame Klassenvariable, die sich an einer festen Stelle im Speicher befindet

  2. volatile : Dieses Schlüsselwort gilt sowohl für class als auch für Instanz Variablen.

Die Verwendung flüchtiger Variablen verringert das Risiko von Speicherkonsistenzfehlern, da jedes Schreiben in eine flüchtige Variable eine Beziehung herstellt, die vor dem Lesen derselben Variablen erfolgt. Dies bedeutet, dass Änderungen an einer flüchtigen Variablen für andere Threads immer sichtbar sind

Schauen Sie sich das an Artikel von Javin Paul um flüchtige Variablen besser zu verstehen.

enter image description here

Fehlt das Schlüsselwort volatile, kann der Wert der Variablen im Stapel der einzelnen Threads unterschiedlich sein. Indem Sie die Variable als volatile definieren, erhalten alle Threads den gleichen Wert im Arbeitsspeicher, und Fehler bei der Speicherkonsistenz wurden vermieden.

Hier kann der Ausdruck variable entweder static (Klassen-) Variable oder instance (Objekt-) Variable sein.

Zu Ihrer Anfrage:

Ein statischer Variablenwert wird auch ein Wert für alle Threads sein. Warum sollten wir uns dann für volatile entscheiden?

Wenn ich in meiner Anwendung die Variable instance benötige, kann ich die Variable static nicht verwenden. Selbst im Fall der Variablen static kann die Konsistenz aufgrund des im Diagramm gezeigten Thread-Cache nicht garantiert werden.

Die Verwendung von volatile -Variablen verringert das Risiko von Speicherkonsistenzfehlern, da jedes Schreiben in eine flüchtige Variable eine Beziehung herstellt, die vor dem Lesen derselben Variablen erfolgt. Dies bedeutet, dass Änderungen an einer flüchtigen Variablen für andere Threads immer sichtbar sind.

Darüber hinaus bedeutet dies, dass ein Thread beim Lesen einer flüchtigen Variablen nicht nur die letzte Änderung der flüchtigen Variable sieht, sondern auch die Nebenwirkungen des Codes, der die Änderung ausgelöst hat => Speicherkonsistenzfehler sind bei flüchtigen Variablen weiterhin möglich. Um Nebenwirkungen zu vermeiden, müssen Sie synchronisierte Variablen verwenden. In Java gibt es jedoch eine bessere Lösung.

Der Zugriff auf einfache atomare Variablen ist effizienter als der Zugriff auf diese Variablen über synchronisierten Code

Einige der Klassen in der Java.util.concurrent package stellt atomare Methoden bereit, die nicht auf der Synchronisation beruhen.

Weitere Informationen finden Sie in diesem High Level Concurrency Control Artikel.

Schauen Sie sich insbesondere Atomvariablen an.

Verwandte SE-Fragen:

Volatile Vs Atomic

Volatile Boolean vs AtomicBoolean

nterschied zwischen flüchtig und synchronisiert in Java

4
Ravindra babu

der flüchtige Zugriff auf variable Werte erfolgt direkt aus dem Hauptspeicher. Es sollte nur in Multithreading-Umgebungen verwendet werden. statische Variable wird einmal geladen. Wenn es in einer Umgebung mit einem einzelnen Thread verwendet wird, wird die Kopie der Variablen aktualisiert, und der Zugriff darauf ist nicht schädlich, da nur ein Thread vorhanden ist.

Wenn nun eine statische Variable in einer Multithreading-Umgebung verwendet wird, treten Probleme auf, wenn das gewünschte Ergebnis erwartet wird. Da jeder Thread eine eigene Kopie hat, spiegelt sich jedes Inkrementieren oder Dekrementieren der statischen Variablen eines Threads möglicherweise nicht in einem anderen Thread wider.

wenn man erwartet, dass die statische Variable die gewünschten Ergebnisse liefert, dann wird alles aufgelöst, wenn man die statische Variable in Multithreading verwendet.

0
Aslam anwer

Nicht sicher, ob statische Variablen im lokalen Thread-Speicher oder NICHT zwischengespeichert sind. Aber als ich zwei Threads (T1, T2) ausgeführt habe, die auf dasselbe Objekt (obj) zugegriffen haben, und als die Aktualisierung durch den T1-Thread auf eine statische Variable erfolgte, spiegelte sich dies in T2 wider.

0
user2779355