Witaj Amigo!

Jest taki obszerny temat o nazwie Java Memory Model. W zasadzie nie musisz jeszcze tego wiedzieć, ale usłyszenie o tym będzie przydatne.

Aby wyeliminować wszystkie możliwe problemy, Java zmieniła sposób działania pamięci. Teraz nie tylko pamięć jest podzielona na lokalną pamięć podręczną wątków i globalną, ale mechanizm stał się jeszcze lepszy.

- I mocniej!

Tak, lepiej i mocniej. To jest jak samolot. Latanie samolotem jest lepsze niż chodzenie, ale trudniejsze. Postaram się wyjaśnić Ci nową sytuację w bardzo uproszczony sposób.

Oto, co wyszło. Do kodu dodano mechanizm synchronizacji lokalnej pamięci wątków, nazwany „happens before” (dosłownie „stało się to wcześniej”). Wymyślono szereg reguł/warunków, po zaistnieniu których następuje synchronizacja pamięci – aktualizacja do stanu aktualnego.

Przykład:

Zamówienie Wątek 1 Wątek 2
1
2

101
102
103
104
105

201
202
203
204
205
public int y = 1;
public int x = 1;

x=2;
synchronized(mutex)
{
 y = 2;
}
wątek czeka na zwolnienie muteksu - mutex

synchronized(mutex)
{
 if (y == x)
 System.out.println("YES");
}

Jednym z tych warunków jest przechwycenie uwolnionego muteksu. Jeśli mutex został zwolniony i ponownie pozyskany, pamięć zostanie zsynchronizowana przed jej pozyskaniem. Wątek 2 zobaczy „najnowsze” wartości x i y, nawet jeśli nie są one zadeklarowane jako ulotne.

- Jakie interesujące. I wiele takich warunków?

Wystarczy, oto kilka warunków synchronizacji pamięci:

  • W ramach jednego wątku każde  polecenie dzieje się przed  (czytaj „dzieje się przed”) każda operacja, która następuje po nim w kodzie źródłowym.
  • Zwolnienie blokady (odblokowania)  następuje przed  przejęciem tej samej blokady (blokady).
  • Wyjście z  zsynchronizowanego  bloku/metody  następuje przed  wejściem do zsynchronizowanego bloku/metody na tym samym monitorze.
  • Zapisywanie niestabilnego pola  ma miejsce przed  odczytaniem tego samego niestabilnego pola.
  • Zakończenie działania metody run instancji klasy Thread  następuje przed  zakończeniem działania metody join() lub zwróceniem przez metodę isAlive() wartości false instancji tego samego wątku.
  • Wywołanie metody start() instancji klasy Thread  następuje przed  uruchomieniem metody run() instancji tego samego wątku.
  • Zakończenie  działania  konstruktora następuje przed rozpoczęciem metody finalize() tej klasy
  • Wywołanie metody przerwania () w wątku  dzieje się przed wątkiem, gdy wątek wykrył, że dana metoda została wywołana, albo przez zgłoszenie wyjątku InterruptedException, albo przy użyciu metod isInterrupted() lub interrupted()

- Tj. wszystko jest trochę bardziej skomplikowane niż myślałem?

Tak, to trochę trudniejsze...

Dziękuję Rysiu, pomyślę o tym.

- Nie przejmuj się tym zbytnio. Nadejdzie czas, wszystko zrozumiesz. Na razie lepiej jest zrozumieć podstawy niż zagłębiać się w tajniki wewnętrznego działania maszyny Java.

— O_o. M-tak. Niektórych rzeczy lepiej nie wiedzieć.