2013-02-25 18 views
6

Ich frage nur in Threading Perspektive ... wahrscheinlich beantwortet viele Male aber bitte helfen Sie mir, dies zu verstehen.Statische Variable vs Volatile

Mit Bezug auf die hier posten Volatile Vs Static in java

eine statische Variable Wert fragen auch einen Wert für alle Fäden sein wird, dann, warum wir für flüchtige gehen sollte? Ich fand folgendes Beispiel:

public class VolatileExample { 
public static void main(String args[]) { 
    new ExampleThread("Thread 1 ").start(); 
    new ExampleThread("Thread 2 ").start(); 
} 

} 
class ExampleThread extends Thread { 
private static volatile int testValue = 1; 
public ExampleThread(String str){ 
    super(str); 
} 
public void run() { 
    for (int i = 0; i < 3; i++) { 
     try { 
      System.out.println(getName() + " : "+i); 
      if (getName().compareTo("Thread 1 ") == 0) 
      { 
       testValue++; 
       System.out.println("Test Value T1: " + testValue); 
      } 
      if (getName().compareTo("Thread 2 ") == 0) 
      { 
       System.out.println("Test Value T2: " + testValue); 
      }     
      Thread.sleep(1000); 
     } catch (InterruptedException exception) { 
      exception.printStackTrace(); 
      } 
     } 
     } 
     } 

Ausgang:

Thread 1 : 0 
Test Value T1: 2 
Thread 2 : 0 
Test Value T2: 2 
Thread 1 : 1 
Test Value T1: 3 
Thread 2 : 1 
Test Value T2: 3 
Thread 1 : 2 
Test Value T1: 4 
Thread 2 : 2 
Test Value T2: 4 

Wenn ich die statische aus dem Testvalue entfernen, so erhält man:

Thread 1 : 0 
Test Value T1: 2 
Thread 2 : 0 
Test Value T2: 1 
Thread 1 : 1 
Test Value T1: 3 
Thread 2 : 1 
Test Value T2: 1 
Thread 1 : 2 
Test Value T1: 4 
Thread 2 : 2 
Test Value T2: 1 

Warum Faden 2 nicht den aktualisierten Wert zu lesen? Wenn es statisch gemacht werden muss, was ist der Gebrauch von volatilen?

Kann jemand Link zu einem guten Beispiel von volatile geben, wo diese Variable nicht statisch deklariert wird.

Dank

+1

Die akzeptierte Rolle Antworte auf den Beitrag, den du verlinkt hast, um deine Frage zu beantworten. –

+2

Lesen Sie den Rest der Antwort - esp. das bisschen über ** statische flüchtige ** .. – Nim

+0

'statisch' =/=' final'. –

Antwort

4

Das Problem ist, dass das ++ nicht atomar ist. Der Code sollte stattdessen AtomicInteger verwenden. Mit der static Variable versuchen beide Threads den gleichen Wert zu aktualisieren, und das ++ ist eigentlich 3 Operationen: get, +1 und speichern. Dies bedeutet, dass zwischen beiden Threads eine Race-Bedingung besteht und diese sich gegenseitig überschreiben.

Warum Thread 2 den aktualisierten Wert nicht liest? Wenn es statisch gemacht werden muss, was ist der Gebrauch von volatilen?

static und volatile verschiedene Dinge tun. static macht das der Klasse zugeordnete Feld im Gegensatz zur Objektinstanz. volatile erzwingt das Lesen oder Schreiben des Feldes, um eine Speicherbarriere zu überwinden. Auf diese Weise können mehrere Threads ein allgemeines Feld lesen und aktualisieren. Dies verhindert jedoch, dass Sie mit nicht vor mehreren Operationen geschützt sind. Wenn Sie die Variable nicht statisch machen, benötigen Sie nicht die volatile, da jeder Thread mit seiner eigenen Instanz des Feldes arbeiten würde.

Sie sollten AtomicInteger verwenden.Bricht ein volatile int sondern bietet auch eine spezielle Handhabung von Zuwachs Operationen:

private static AtomicInteger testValue = new AtomicInteger(1); 
... 
testValue.incrementAndGet(); 

jemand Link zu einem guten Beispiel für volatile geben kann, wo diese Variable nicht statisch deklarieren.

Sie würden ein volatile in einem nicht statischen Feld benötigen, wenn es von mehreren Threads geteilt wurde. Wenn Sie beispielsweise die testValue in die Klasse VolatileExample verschoben und dann dieselbe Instanz der Klasse VolatileExample in beide Threads übergeben haben, können sie auf testValue zugreifen.

+0

Danke für Sie wertvolle Einsicht, ich werde das gleiche testen, die Variable zu halten anderswo. – Dhananjay

+0

Nur um es noch einmal zu wiederholen: Sie können kein '' '' '' '' 'auf einem' 'volatilen'' machen, egal ob es sich um ein statisches oder nicht @Dhananjay handelt. – Gray

+0

Ich habe versucht, die Variable außerhalb der Klasse Runnable zu setzen.
' öffentliche Klasse Konto { öffentliche Doppelbalance = 0; public static void main (Zeichenfolge ... s) { Konto aAccount = new Account(); DepositThread aPositonThread1 = neuer DepositThread (aAccount); Thread thread1 = neuer Thread (a DepositThread1, "thread1"); DepositThread1 a DepositThread2 = Neu DepositThread1 (aAccount); Thread thread2 = neuer Thread (a DepositThread2, "thread2"); thread1.start(); thread2.start(); } } ' Aber wenn wir das gleiche Objekt in zwei Thread übergeben, wird es trotzdem den aktualisierten Wert bekommen? – Dhananjay

4

Die Verwendung von volatile ist, um sicherzustellen, dass alle Fäden den gleichen Wert zur gleichen Zeit zu sehen. Im Wesentlichen heißt es, dass diese Variable niemals zwischengespeichert werden sollte.

Es ist schwierig, im Code zu demonstrieren, da Cache-Strategien von CPU zu CPU und von JRE zu JRE wechseln.

Was volatile ist mit dem JRE sagen will, ist Wenn Sie jemals versucht werden, diesen Wert cachen, weil Sie denken, dass Sie den Code machen könnte ein wenig schneller laufen durch so tun ... DONT! ... Ich weiß viel mehr über Programmierung als Sie und ich weiß ohne Zweifel, dass wenn Sie das tun, Sie meinen Code brechen werden..

0

In diesem Fall, wenn tou die static Modifikator Sie die Variable geändert entfernt, weil jetzt jeder ExampleThread seine eigene testValue hat, denn das ist der Speicherwert für jeden Thread-Instanz anders.

Bedeutung der static Modifikator:

Manchmal wollen Sie Variablen haben, die auf alle Objekte gemeinsam sind. Dies wird mit dem statischen Modifikator erreicht. Felder mit dem statischen Modifikator in ihrer Deklaration heißen statische Felder oder Klassenvariablen. Sie sind mit der Klasse assoziiert und nicht mit irgendeinem Objekt. Jede Instanz der Klasse teilt eine Klassenvariable, die sich an einem festen Ort im Speicher befindet. Jedes Objekt kann den Wert einer Klassenvariablen ändern ...

Referenz: Understanding Instance and Class Members

Über volatile, wenn Sie eine andere Art von Test versuchen, Bewegen der testValue Variable in die Klasse VolatileExample, wie folgt aus:

public class VolatileExample { 
    private volatile int testValue = 1; 
... 
} 

Dann entfernen Sie die testVariable von ExampleThread und den Code ausführen. Seine Ausgabe sollte wie die erste sein.

Bedeutung des volatile Modifikator:

Mit flüchtigen Variablen reduziert das Risiko von Speicherkonsistenzfehler, da jeder Schreibvorgang in eine volatilen Variable stellt ein geschieht zuvor Beziehung mit anschließendem dem gleichen Variable liest. Das bedeutet, dass Änderungen an einer flüchtigen Variable auf andere Threads immer sichtbar sind

Referenz: Atomic Access

0

Ihre letzte Frage „jemand Link zu einem guten Beispiel für volatile geben kann, wo diese Variable nicht statisch ist, erklären. " gemacht, um dieses Konzept klar zu verstehen, und ich kam mit einem Beispiel.

public class VolatileExample { 

    // public static volatile int testValue = 1; 
    public int nonstatic=8; 
    public static void main(String args[]) { 
     VolatileExample volatileExample=new VolatileExample(); 
     new ExampleThread("Thread 1 ",volatileExample).start(); 
     new ExampleThread("Thread 2 ",volatileExample).start(); 
    } 

} 
class ExampleThread extends Thread { 
VolatileExample volatileExample; 
    public ExampleThread(String str,VolatileExample volatileExample){ 
     super(str); 
     this.volatileExample=volatileExample; 
    } 
    public void run() { 
     for (int i = 0; i < 3; i++) { 
      try { 
       if (getName().compareTo("Thread 1 ") == 0) 
       { 
        volatileExample.nonstatic++; 
        System.out.println("Test Value T1: " + volatileExample.nonstatic); 


       } 
       if (getName().compareTo("Thread 2 ") == 0) 
       { 
        System.out.println("Test Value T2: " + volatileExample.nonstatic); 
        Thread.sleep(1); 
       } 
       // Thread.sleep(1000); 
      } catch (InterruptedException exception) { 
       exception.printStackTrace(); 
      } 
     } 
    } 
} 

jetzt bitte sehen Sie die Änderung, indem Sie public int nonstatic = 8; volatile

Nach der Ausgabe wäre, wenn es flüchtig gemacht wird,

Testwert T1: 9 Testwert T1: 10 Testwert T1: 11 Testwert T2: 11 Testwert T2: 11 Testwert T2: 11

Prozess beendet mit Exit-Code 0

Nach dem Ergebnis wird, wenn es nicht flüchtige hergestellt: Testwert T1: 9 Testwert T2 Wert T1 9 Test:: 10 Testwert T1: 11 Testwert T2: 11 Testwert T2: 11

Prozess mit Exit-Code abgeschlossen 0

Beobachtung: Da Volatile KeyWord macht den Faden direkt schreibe es in den Hauptspeicher, Thread wird schneller zurück in die Schleife, also wenn es flüchtig gemacht wird, beendete Thread1 seine Aufgabe schneller und kam zurück in die Schleife, noch bevor Thread2 seinen Zug begann.

Auf der anderen Seite, so dass es nichtflüchtig ist, macht der Thread seinen Locl-Cache zu aktualisieren und dann an den Hauptspeicher zu melden ... so während dieses Zyklus, thread2 trat das Rennen.

PLz beachten Sie, ich habe "nicht-statische" Variable in VolatileExample-Klasse nicht in ExampleThread, um dies zu demonstrieren.

Ihre andere Frage ist: Warum Thread 2 den aktualisierten Wert nicht liest? Wenn es statisch gemacht werden muss, was ist der Gebrauch von volatilen?

Nun, wenn u es Testvalue nicht statisch, dann wird ihr nichts anderes als zwei verschiedene Objekte Thread1 und Thread2 der Klasse machen ExampleThread auf ihre eigenen Arbeiten Zugriffe auf Variablen Testvalue .... so flüchtig tut wirklich ..

Verwandte Themen