2016-08-20 12 views
5

Przeczytałem "Zrozumienie zaawansowanych funkcji i najlepszych praktyk JVM", który zawiera segment kodu, który wyjaśnia dzieje - przed regułą w java. Nie rozumiem. Kod jest poniżej:, jeśli wątek A rozpoczyna się przed wątkiem B w języku Java, to A zostanie zaplanowane przez os przed B?

private int value = 0; 
//executed by Thread A 
public void setValue(int value){ 
    this.value = value; 
} 
//executed by Thread B 
public void getValue(){ 
    return value; 
} 

Załóżmy, że gwint A starty przed wątku B w kodzie. Rozumiem, że nie znamy wyniku zwróconego przez getValue() w wątku B, ponieważ nie jest bezpieczny dla wątków. Ale książka mówi, czy dodać zsynchronizowane słowo kluczowe do funkcji setValue() i getValue(), to nie istnieje problem bezpieczny wątek i metoda zwróci właściwą wartość. Książka wyjaśnia, że ​​ponieważ synchronized spotyka się z dzieje się przed reguły. Mam więc dwa pytania poniżej kodu.

public class VolatileDemo3 { 
    private volatile int value = 0; 
    public static void main(String[] args) { 
     VolatileDemo3 v = new VolatileDemo3(); 
     Thread A = new Thread(v.new Test1());// Thread A 
     Thread B = new Thread(v.new Test2());//Thread B 
     A.start(); 
     B.start(); 
    } 
    public void setValue(int value){ 
     this.value = value; 
    } 
    public int getValue(){ 
     return this.value; 
    } 

    public class Test1 implements Runnable { 
     @Override 
     public void run() { 
      setValue(10); 
     } 
    } 
    public class Test2 implements Runnable { 
     @Override 
     public void run() { 
      int v = getValue(); 
      System.out.println(v); 
     } 
    } 
} 
  1. Chociaż A.start() prowadzony przed B.start() i wartości jest volatile, nie możemy zapewnić gwint B może wydrukować 10, prawda? Ponieważ wątek B jest możliwe zaplanowane najpierw przez JVM, a następnie wątek B będzie drukować 0 nie 10.
  2. Nawet jeśli wątek A zaplanowane przed wątku B przez JVM, ale również nie może zagwarantować, że instrukcja this.value = value realizowane przez JVM ponieważ przed return this.value JVM będzie ponownie sortować instrukcje. Czy zrozumienie jest słuszne? Proszę pomóż mi.
+3

Istnieje różnica między "bezpiecznym wątkiem" i "przewidywalnym". Dodanie opcji 'zsynchronizowany' będzie oznaczać, że wątek B zawsze będzie wyświetlał wartość' prawidłowość_ ', ale może jeszcze nie zostać zaktualizowana. Jak podkreślasz, nie ma gwarancji, że te dwa wątki będą wykonywane w założonej kolejności. Bez 'zsynchronizowanej 'nie ma gwarancji _visibility_, więc nawet jeśli A zostanie wykonane najpierw, B może nadal widzieć starą" wartość ". –

+0

Myślę, że źle czytasz. Jeśli istnieje słowo kluczowe "zsynchronizowane", oznacza to, że JVM zagwarantuje, że w danym momencie nie można mieć dwóch wątków wykonujących jednocześnie "setValue" i "getValue" (jeden będzie musiał zakończyć wykonywanie metody przed inny wątek może wprowadzić inną metodę). Nie * nie * gwarantuje niczego na temat kolejności tych operacji. – Paolo

+1

Aby zapewnić "poprawną" widoczność, należy zadeklarować 'private volatile int value = 0;'. To sprawia, że ​​napisana wartość jest widoczna po wszystkich pozostałych wątkach. – PeterMmm

Odpowiedz

9

Kwestia „zdarzyło” nie jest to, że powoduje to wkręcić, aby ustawić wartość przed wątku B. To, że chociaż może się zdarzyć, że nawlec dostał się do this.value = value chronologicznie przed wątek B lecieć getValue , wartość B może nadal być starą wartością.

Oznacza to, że w środowisku z gwintem, nawet jeśli dwie instrukcje są wykonywane w porządku chronologicznym, nie oznacza to, że wyniki jednego będą widoczne dla drugiego.

Jeśli wątek B najpierw wywołał tę metodę, zawsze otrzyma starą wartość. Ale jeśli zdarzy się, że wywołamy tę metodę jako drugą, nie wiadomo, czy otrzyma ona starą czy nową wartość.

Z tego powodu musisz użyć środków, aby zapewnić regułę "zdarzają się przed", a następnie wiesz, że wyniki tego, co "stało się wcześniej", są widoczne po tym, co "dzieje się po".

Jeśli na przykład jest niestabilny, zapewnia, że ​​jeśli setValue() zostanie wywołany przez wątek A przed wątkiem B, wątek B zobaczy nową wartość.

 
╔═════════════════════╤════════════════════════╤═════════════════════╗ 
║ Order of operations │ Are we using   │ What value of value ║ 
║      │ volatile/synchronized? │ will B see?   ║ 
╠═════════════════════╪════════════════════════╪═════════════════════╣ 
║ A runs setValue(10) │ N      │ Unknown    ║ 
║ B runs getValue() ├────────────────────────┼─────────────────────╢ 
║      │ Y      │ 10     ║ 
╟─────────────────────┼────────────────────────┼─────────────────────╢ 
║ B runs getValue() │ N      │ 0     ║ 
║ A runs setValue(10) ├────────────────────────┼─────────────────────╢ 
║      │ Y      │ 0     ║ 
╚═════════════════════╧════════════════════════╧═════════════════════╝ 

chodzi swoimi dwoma pytaniami:

  1. True. Nie możesz wiedzieć, który z nich dostanie się do tej instrukcji. Nie chodzi tylko o to, który wątek jest zaplanowany jako pierwszy. Wątki mogą być uruchomione na różnych procesorach, jeden procesor może wymagać długiego pobierania pamięci, drugi tylko krótkiego pobierania pamięci, więc jest wolniejszy od drugiego. Możliwe też, że instrukcje maszynowe w przygotowaniu do kodu mają różną długość. Ogólnie rzecz biorąc, po prostu nie wiesz, co dzieje się za kulisami, a Java nie daje żadnych gwarancji co do kolejności uruchamiania wątków.
  2. Jest mało prawdopodobne, aby instrukcje zostały zmienione w tym konkretnym przypadku, ponieważ metody są bardzo krótkie.Ponownie, nie możesz powiedzieć, co się dzieje, ponieważ zależy to od konkretnej maszyny JVM, liczby procesorów, typu procesora, harmonogramu i układu pamięci - nie masz żadnych gwarancji.
+0

To jest prawdziwy problem, wszyscy inni zupełnie nie rozumieją. –

+0

Matryca warunków i wyników jest naprawdę fajna. –

+0

Bardzo dziękuję @RealSkeptic. Ale muszę zadbać o fudrther. Widziany poniżej kod – sunny

0

Dodajesz zsynchronizowane z funkcjami setValue/getValue zakłada, że ​​każdy wątek, który chce wykonać ten fragment kodu, najpierw będą musiały uzyskać (lub czekać) na blokadę na tym obiekcie.

Jeśli założymy, że żadne blokady nie są utrzymywane przed wywołaniem wątku A setValue/getValue, wątek A natychmiast otrzyma blokadę. Jednak w międzyczasie, jeśli wątek B wywoła setValue/getValue, będzie musiał poczekać, aż wątek A zrezygnuje z blokady, zanim będzie mógł wykonać tę metodę.

Jednak, gdy oba wątki czekały na blokadę obiektu, nie możemy zagwarantować, który z nich byłby pierwszy wybrany przez system operacyjny.

Powiązane problemy