2013-02-25 15 views
6

Pytam tylko z perspektywy wątków ... prawdopodobnie wiele razy odpowiadałem, ale proszę, pomóż mi to zrozumieć.Zmienna statyczna kontra volatile

Nawiązując do posta tutaj Volatile Vs Static in java

prosząc statyczną wartość zmiennej jest również będzie jedna wartość dla wszystkich wątków, to dlaczego mamy iść za niestabilne? Znalazłem następujący przykład:

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(); 
      } 
     } 
     } 
     } 

wyjściowa:

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 

Jeśli usunąć statyczne z testValue, uzyskany wynik:

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 

Dlaczego nić 2 nie czyta zaktualizowaną wartość? Jeśli to musi być zrobione statycznie, jak używać niestabilnego?

Czy ktoś może podać link do dobrego przykładu zmiennej, w której ta zmienna nie jest statyczna.

Dzięki

+1

Przyjęty odpowiedź na post, który łączyłeś, aby odpowiedzieć na twoje pytanie. –

+2

Przeczytaj resztę odpowiedzi - szczególnie. bit o wartości ** static volatile ** .. – Nim

+0

'static' =/=' final'. –

Odpowiedz

4

Problem polega na tym, że ++ nie jest atomowy. Kod powinien używać zamiast tego AtomicInteger. W przypadku zmiennej static oba wątki próbują zaktualizować tę samą wartość, a ++ jest w rzeczywistości 3 operacjami: get, +1 i store. Oznacza to, że pomiędzy obydwoma wątkami istnieje warunek wyścigu i nadpisują się nawzajem.

Dlaczego wątek 2 nie odczytuje zaktualizowanej wartości? Jeśli to musi być zrobione statycznie, jak używać niestabilnego?

static i volatile robić różne rzeczy. static powoduje, że pole powiązane z klasą jest przeciwieństwem instancji obiektu. volatile wymusza odczyt lub odczyt pola, aby przekroczyć barierę pamięci. Dzięki temu wiele wątków może odczytać i zaktualizować typowe pole, ale nie chroni przed wieloma operacjami. Jeśli zmienna zostanie zmieniona na , to nie będzie potrzebna volatile, ponieważ każdy wątek będzie działał z własną instancją tego pola. Należy użyć AtomicInteger.Ten okłady volatile int ale zapewnia również specjalnego traktowania operacji inkrementacji:

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

Może ktoś podać link dobry przykład lotny gdzie ta zmienna nie jest zadeklarować statyczne.

Potrzebowałbyś volatile na polu niestatycznym, gdy był współużytkowany przez wiele wątków. Na przykład, jeśli przeniesiono klasę testValue do klasy VolatileExample, a następnie przekazano tę samą instancję klasy VolatileExample do obu wątków, aby uzyskać dostęp do testValue.

+0

Dziękuję za tobie cenny wgląd, testuję to samo, zachowując zmienną gdzie indziej. – Dhananjay

+0

Aby powtórzyć, nie można zrobić '++' na 'volatile' bez względu na to czy jest statyczne czy nie @Dhananjay. – Gray

+0

Próbowałem umieścić zmienną poza klasą Runnable.
' Konto publiczne klasy { publiczny podwójny bilans = 0; public static void main (String ... s) { Konto aAccount = nowe konto(); DepositThread aDepositThread1 = new DepositThread (aAccount); Wątek thread1 = new Thread (aDepositThread1, "thread1"); DepositThread1 aDepositThread2 = new DepositThread1 (aAccount); Wątek thread2 = new Thread (aDepositThread2, "thread2"); thread1.start(); thread2.start(); } } ' Ale jeśli przekazujemy ten sam obiekt w dwóch wątkach, to czy mimo to otrzymamy zaktualizowaną wartość? – Dhananjay

4

Zastosowanie volatile jest zapewnienie, że wszystkie wątki zobaczyć samą wartość w tym samym czasie. Zasadniczo mówi się, że tej zmiennej nigdy nie należy buforować.

Trudno jest wykazać w kodzie, ponieważ strategie buforowania zmieniają się z cpu na cpu iz JRE na JRE.

Co volatile mówi do JRE jest Jeśli kiedykolwiek skłonna do pamięci podręcznej tej wartości, ponieważ sądzę, że można dokonać kod uruchomić nieco szybciej w ten sposób ... NIE! ... Znam więcej o programowaniu niż ja i wiem bez cienia wątpliwości, że jeśli to zrobisz, złamiesz mój kod..

0

W tym przypadku, kiedy tou usunął static modyfikator zmieniłeś zmienną, bo teraz każda ExampleThread posiada własny testValue, na który wartość pamięci jest inna dla każdej instancji gwintu.

Znaczenie static modyfikatora:

Czasem chcesz mieć zmiennych, które są wspólne dla wszystkich obiektów. Osiąga się to za pomocą modyfikatora statycznego. Pola, które mają w swojej deklaracji modyfikator statyczny, są nazywane polami statycznymi lub zmiennymi klasy. Są one związane z klasą, a nie z jakimkolwiek obiektem. Każda instancja klasy ma wspólną zmienną klasy, która znajduje się w jednej stałej lokalizacji w pamięci. Każdy obiekt może zmienić wartość zmiennej klasy ...

referencyjny: Understanding Instance and Class Members

O volatile, jeśli wypróbować inny rodzaj testu, poruszając zmienną testValue do klasy VolatileExample, jak poniżej:

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

Następnie wyjąć testVariable z ExampleThread i uruchomić kod. Jego wynik powinien być taki jak pierwszy.

Znaczenie volatile modyfikatora:

Używanie zmiennych lotnych zmniejsza ryzyko błędów spójności pamięci, ponieważ każdy zapis do zmiennej lotnych ustanawia się dzieje, zanim relacje z kolejnych odsłon tej samej zmiennej. Oznacza to, że zmiany zmiennej lotnych zawsze są widoczne dla innych wątków

referencyjny: Atomic Access

0

Twoje ostatnie pytanie „Czy ktoś może podać link dobry przykład lotny gdzie ta zmienna nie jest zadeklarować statyczne. " aby zrozumieć tę koncepcję wyraźnie i przyjechałem z przykładem.

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(); 
      } 
     } 
    } 
} 

teraz proszę zobaczyć zmianę przez uczynienie publicznym int nonstatic = 8; lotny

Poniżej podano wyjście, gdy jest lotna

wartość próby T1: 9 wartość próby T1: 10 wartość próby T1: 11 wartość próby T2 11 wartość próby T2 11 Wartość Teście T2 11

Proces zakończony z kodem wyjściowym 0

Poniżej wyniku, jeżeli jest wykonana nielotne: testu Wartość T1: 9 Test wartości T2 : 9 wartość próby T1: 10 wartość próby T1: 11 wartość próby T2 11 wartość próby T2 11

Proces zakończony z kodem wyjściowym 0

obserwacji: Ponieważ lotny słowa kluczowego wpływa gwint do bezpośredniego zapisz go w głównej pamięci, wątek wraca szybciej do pętli, a więc gdy jest zmienny, wątek1 szybciej wykonał zadanie i wrócił do pętli jeszcze przed rozpoczęciem wątku.

Po drugiej stronie, czyniąc ją nieulotną, powoduje, że wątek aktualizuje pamięć podręczną miejscówki, a następnie raportuje ją do pamięci głównej ... tak, aby podczas tego cyklu wątek2 wszedł do wyścigu.

PLz uwaga, mam "niestatyczną" zmienną w klasie VolatileExample nie w ExampleThread, aby to zademonstrować.

Twoje drugie pytanie brzmi: Dlaczego wątek 2 nie odczytuje zaktualizowanej wartości? Jeśli to musi być zrobione statycznie, jak używać niestabilnego?

Dobrze, jeśli u sprawiają, że testValue non-statyczne, to jej nic, ale dwa różne obiekty thread1 i thread2 klasy ExampleThread działa na własną rękę varibles testValue .... tak lotny nie robi to większego znaczenia ..

Powiązane problemy