"Cześć, Amigo!"
"Cześć, Ellie!"
„Chcę ci opowiedzieć o lotnym modyfikatorze. Wiesz, co to jest?”
— Coś związanego z nitkami. Nie pamiętam dokładnie.
„Więc słuchaj. Oto kilka szczegółów technicznych dla Ciebie:”
„Komputer ma dwa rodzaje pamięci: pamięć globalną (zwykłą) i pamięć wbudowaną w procesor. Wbudowana pamięć procesora jest podzielona na rejestry, pamięć podręczną pierwszego poziomu (L1), pamięć podręczną drugiego poziomu (L2) i trzeci poziom (L3).”
„Te typy pamięci mają różne prędkości. Najszybszą i najmniejszą pamięcią są rejestry, następnie pamięć podręczna procesora (L1, L2, L3), a na koniec pamięć globalna (najwolniejsza).”
„Pamięć globalna i pamięć podręczna procesora działają z bardzo różnymi prędkościami, więc maszyna Java umożliwia każdemu wątkowi przechowywanie najczęściej używanych zmiennych w lokalnej pamięci wątków (w pamięci podręcznej procesora).”
„Czy ten proces można jakoś kontrolować?”
„Niezupełnie. Całą pracę wykonuje maszyna Java. Jest bardzo inteligentna, jeśli chodzi o optymalizację wydajności”.
„Ale właśnie dlatego ci to mówię. Jest jeden mały problem. Kiedy dwa wątki pracują z tą samą zmienną, każdy z nich może przechowywać kopię we własnej lokalnej pamięci podręcznej. Wtedy jeden wątek może zmienić zmienną, ale drugi może nie zauważyć zmiany, ponieważ nadal działa z własną kopią zmiennej”.
— Cóż, w takim razie można zrobić?
„Twórcy Javy przewidzieli specjalne słowo kluczowe dla tej sytuacji: volatile. Jeśli zmienna jest dostępna z różnych wątków, należy ją oznaczyć modyfikatorem volatile, aby maszyna Java nie umieszczała jej w pamięci podręcznej. Tak zwykle wygląda:
public volatile int count = 0;
- Och, pamiętam. Już o tym wspominałeś. Ja już to wiem.
- Pewnie, że tak. Ale przypomniałeś sobie o tym dopiero wtedy, gdy ci powiedziałem.
– Eee, trochę zapomniałem.
„Powtórzenie jest matką nauki!”
„Oto kilka nowych faktów na temat modyfikatora volatile. Modyfikator volatile gwarantuje jedynie, że zmienna będzie bezpiecznie odczytywana i zapisywana. Nie gwarantuje jednak, że zostanie ona bezpiecznie zmieniona”.
"Co za różnica?"
„Spójrz, jak zmienia się zmienna:”
Kod | Co naprawdę się dzieje: | Opis |
---|---|---|
|
|
Krok 1. Wartość licznika zmiennej jest kopiowana z pamięci globalnej do rejestru procesora. Krok 2. Krok 3. |
„Wow! Więc wszystkie zmienne są zmieniane tylko w procesorze?”
"Tak."
„A wartości są kopiowane tam iz powrotem: z pamięci do procesora iz powrotem?”
"Tak."
„Modyfikator volatile gwarantuje, że po uzyskaniu dostępu do zmiennej count zostanie ona odczytana z pamięci (krok 1). A jeśli wątek chce przypisać nową wartość, na pewno znajdzie się ona w pamięci globalnej (krok 3).”
„Ale maszyna Java nie gwarantuje, że nie będzie żadnego przełączania wątków między krokami 1 i 3”.
„Więc zwiększenie zmiennej o 1 to tak naprawdę trzy operacje?”
"Tak."
„A jeśli dwa wątki jednocześnie chcą wykonać count ++, to mogą sobie przeszkadzać?”
"Tak, sprawdź to:"
Wątek 1 | Wątek 2 | Wynik |
---|---|---|
|
|
|
„Więc możesz uzyskać dostęp do zmiennej, ale jej zmiana jest nadal ryzykowna?”
„Cóż, możesz to zmienić, tylko bądź ostrożny ☺”
"Jak?"
„ Zsynchronizowany jest naszym najlepszym przyjacielem”.
"Widzę."
GO TO FULL VERSION