volatile
ma semantykę widoczności pamięci. Zasadniczo wartość volatile
pola staje się widoczna dla wszystkich czytelników (w szczególności innych wątków) po zakończeniu operacji zapisu. Bez tego volatile
czytelnicy mogliby zobaczyć nie zaktualizowaną wartość.
Aby odpowiedzieć na twoje pytanie: Tak, używam volatile
zmiennej, aby kontrolować, czy jakiś kod kontynuuje pętlę. Pętla sprawdza volatile
wartość i kontynuuje, jeśli jest true
. Warunek można ustawić false
, wywołując metodę „stop”. Pętla widzi false
i kończy się, gdy testuje wartość po zakończeniu wykonywania metody zatrzymania.
Książka „ Java Concurrency in Practice ”, którą gorąco polecam, daje dobre wyjaśnienie volatile
. Ta książka została napisana przez tę samą osobę, która napisała artykuł IBM wymieniony w pytaniu (w rzeczywistości cytuje swoją książkę na dole tego artykułu). Używam tego, volatile
co jego artykuł nazywa „flagą statusu wzorca 1”.
Jeśli chcesz dowiedzieć się więcej o tym, jak volatile
działa pod maską, przeczytaj model pamięci Java . Jeśli chcesz wyjść poza ten poziom, sprawdź dobrą książkę o architekturze komputerowej, taką jak Hennessy i Patterson, i poczytaj o spójności i spójności pamięci podręcznej.
volatile
która pojawiła się wraz z nowym modelem pamięci Java zdefiniowanym w JSR 133: że gdy wątek czytavolatile
zmienną, widzi nie tylko wartość ostatnio zapisaną przez inny wątek, ale także wszystkie inne zapisuje do innych zmiennych, które były widoczne w tym drugim wątku w momencievolatile
pisania. Zobacz tę odpowiedź i odniesienie .„… Zmienny modyfikator gwarantuje, że każdy wątek odczytujący pole zobaczy ostatnią zapisaną wartość”. - Josh Bloch
Jeśli zastanawiasz się nad użyciem
volatile
, przeczytaj pakiet,java.util.concurrent
który dotyczy zachowania atomowego.Wpis w Wikipedii na temat wzorca Singleton pokazuje niestabilność w użyciu.
źródło
volatile
isynchronized
słowa kluczowe?volatile
przykładu. Można go znaleźć w zarchiwizowanej wersji .void
ipublic
słowa kluczowe”.Ważna uwaga na temat
volatile
:synchronized
ivolatile
i zamki.synchronized
zmiennej. Używaniesynchronized
słowa kluczowego ze zmienną jest nielegalne i spowoduje błąd kompilacji. Zamiast używaćsynchronized
zmiennej w Javie, możesz użyćvolatile
zmiennej java , która poinstruuje wątki JVM, aby odczytały wartośćvolatile
zmiennej z pamięci głównej i nie buforowały jej lokalnie.volatile
słowa kluczowego.źródło
Przykładowe użycie
volatile
:Instancję tworzymy leniwie w momencie otrzymania pierwszego żądania.
Jeśli nie utworzymy
_instance
zmiennej,volatile
Wątek, który tworzy instancję,Singleton
nie będzie w stanie komunikować się z drugim wątkiem. Więc jeśli wątek A tworzy instancję Singleton i zaraz po utworzeniu, procesor psuje itp., Wszystkie inne wątki nie będą mogły zobaczyć wartości_instance
jako nie zerowej i będą wierzyć, że wciąż jest przypisana zerowa.Dlaczego to się dzieje? Ponieważ wątki czytnika nie blokują się i dopóki wątek zapisujący nie wyjdzie z synchronizowanego bloku, pamięć nie zostanie zsynchronizowana, a wartość
_instance
nie zostanie zaktualizowana w pamięci głównej. W przypadku słowa kluczowego Volatile w Javie jest to obsługiwane przez samą Javę i takie aktualizacje będą widoczne dla wszystkich wątków czytelników.Przykładowe użycie bez lotnych:
Powyższy kod nie jest bezpieczny dla wątków. Mimo że ponownie sprawdza wartość instancji w bloku zsynchronizowanym (ze względu na wydajność), kompilator JIT może zmienić porządek kodu bajtowego w taki sposób, aby odwołanie do instancji zostało ustawione przed zakończeniem wykonywania przez konstruktor. Oznacza to, że metoda getInstance () zwraca obiekt, który mógł nie zostać całkowicie zainicjowany. Aby kod był bezpieczny dla wątków, można użyć słowa kluczowego volatile od Java 5 dla zmiennej instancji. Zmienne oznaczone jako lotne są widoczne tylko dla innych wątków, gdy konstruktor obiektu całkowicie zakończy wykonywanie.
Źródło
volatile
użycie w Javie :Szybkie iteratory są zwykle implementowane przy użyciu
volatile
licznika na obiekcie listy.Iterator
bieżąca wartość licznika jest osadzana wIterator
obiekcie.Iterator
wykonywana jest operacja, metoda porównuje dwie wartości licznika i wyrzuca a,ConcurrentModificationException
jeśli są one różne.Implementacja iteratorów odpornych na awarie jest zwykle niewielka. Zazwyczaj polegają na właściwościach struktur danych implementacji określonej listy. Nie ma ogólnego wzorca.
źródło
private static final Singleton _instance;
.volatile
jest bardzo przydatny do zatrzymywania wątków.Nie dlatego, że powinieneś pisać własne wątki, Java 1.6 ma wiele fajnych pul wątków. Ale jeśli jesteś pewien, że potrzebujesz wątku, musisz wiedzieć, jak go zatrzymać.
Wzór, którego używam do wątków, to:
W powyższym segmencie kodu odczyt wątku
close
w pętli while różni się od tego, który wywołujeclose()
. Bez lotnego wątek prowadzący pętlę może nigdy nie zobaczyć zmiany zamykania.Zauważ, że nie ma potrzeby synchronizacji
źródło
volatile
słowa kluczowego, i zawsze wydaje się działać dobrze.Jednym z powszechnych przykładów użycia
volatile
jest użycievolatile boolean
zmiennej jako flagi do zakończenia wątku. Jeśli rozpocząłeś wątek i chcesz móc bezpiecznie przerwać go z innego wątku, możesz okresowo sprawdzać flagę. Aby go zatrzymać, ustaw flagę na true. Tworząc flagęvolatile
, możesz upewnić się, że sprawdzający ją wątek zobaczy, że został ustawiony przy następnym sprawdzeniu, nawet bez użyciasynchronized
bloku.źródło
Zmienna zadeklarowana za pomocą
volatile
słowa kluczowego ma dwie główne cechy, dzięki którym jest wyjątkowa.Jeśli mamy zmienną zmienną, nie można jej buforować do pamięci podręcznej komputera (mikroprocesora) żadnym wątkiem. Dostęp zawsze odbywał się z pamięci głównej.
Jeśli operacja zapisu przebiega na zmiennej zmiennej i nagle żądana jest operacja odczytu , gwarantuje się, że operacja zapisu zostanie zakończona przed operacją odczytu .
Dwie powyższe cechy to dedukują
Z drugiej strony
volatile
słowo kluczowe jest idealnym sposobem na utrzymanie wspólnej zmiennej, która ma „n” liczbę wątków czytnika i tylko jeden wątek zapisujący, aby uzyskać do niej dostęp. Po dodaniuvolatile
słowa kluczowego jest to gotowe. Żadnych innych kosztów związanych z bezpieczeństwem nici.Odwrotnie,
Nie możemy używać
volatile
słowa kluczowego wyłącznie w celu zaspokojenia wspólnej zmiennej, która ma dostęp do więcej niż jednego wątku pisującego .źródło
Nikt nie wspominał o traktowaniu operacji odczytu i zapisu dla typu długiej i podwójnej zmiennej. Odczyty i zapisy są operacjami atomowymi dla zmiennych referencyjnych i większości prymitywnych zmiennych, z wyjątkiem typów długich i podwójnych zmiennych, które muszą używać zmiennego słowa kluczowego, aby być operacjami atomowymi. @połączyć
źródło
Tak, zmienna musi być używana, gdy chcesz, aby zmienna zmienna była dostępna dla wielu wątków. Nie jest to bardzo częsty przypadek użycia, ponieważ zazwyczaj musisz wykonać więcej niż jedną operację atomową (np. Sprawdź stan zmiennej przed jej modyfikacją), w którym to przypadku zamiast tego użyjesz zsynchronizowanego bloku.
źródło
Moim zdaniem dwa ważne scenariusze inne niż zatrzymanie wątku, w których używane jest niestabilne słowo kluczowe:
źródło
Będziesz musiał użyć słowa kluczowego „niestabilnego” lub „zsynchronizowanego” oraz wszelkich innych narzędzi i technik kontroli współbieżności, które możesz mieć do dyspozycji, jeśli tworzysz aplikację wielowątkową. Przykładem takiej aplikacji są aplikacje komputerowe.
Jeśli tworzysz aplikację, która zostałaby wdrożona na serwerze aplikacji (Tomcat, JBoss AS, Glassfish itp.), Nie musisz samodzielnie obsługiwać kontroli współbieżności, ponieważ jest ona już adresowana przez serwer aplikacji. W rzeczywistości, jeśli dobrze zapamiętałem, standard Java EE zabrania jakiejkolwiek kontroli współbieżności w serwletach i EJB, ponieważ jest on częścią warstwy „infrastruktury”, którą powinieneś być wolny od obsługi. Kontrolę współbieżności wykonujesz w takiej aplikacji tylko wtedy, gdy implementujesz obiekty singletonowe. Ten problem został rozwiązany nawet w przypadku łączenia elementów za pomocą frameworkd, takich jak Spring.
Tak więc w większości przypadków programowania Java, w których aplikacja jest aplikacją internetową i używa frameworka IoC, takiego jak Spring lub EJB, nie trzeba używać „niestabilności”.
źródło
volatile
gwarantuje tylko, że wszystkie wątki, nawet same, rosną. Na przykład: licznik widzi tę samą powierzchnię zmiennej w tym samym czasie. Nie jest używany zamiast zsynchronizowanego, atomowego lub innego, całkowicie synchronizuje odczyty. Proszę nie porównywać go z innymi słowami kluczowymi Java. Jak pokazano w poniższym przykładzie, operacje na zmiennych lotnych są również atomowe, nie udaje im się to od razu.Nawet niestabilne lub nie, wyniki zawsze będą się różnić. Ale jeśli użyjesz AtomicInteger, jak poniżej, wyniki będą zawsze takie same. To samo dotyczy również synchronizacji.
źródło
Tak, używam go dość często - może być bardzo przydatny w przypadku kodu wielowątkowego. Artykuł, który wskazałeś, jest dobry. Chociaż należy pamiętać o dwóch ważnych sprawach:
źródło
Każdy wątek uzyskujący dostęp do zmiennego pola odczyta jego bieżącą wartość przed kontynuowaniem, zamiast (potencjalnie) przy użyciu buforowanej wartości.
Tylko zmienna składowa może być lotna lub przejściowa.
źródło
Zdecydowanie tak. (I to nie tylko w Javie, ale także w języku C #). Są chwile, kiedy trzeba uzyskać lub ustawić wartość, która na pewno gwarantuje działanie atomowe na danej platformie, na przykład int lub boolean, ale nie wymaga nadwyżka blokady gwintu. Zmienne słowo kluczowe pozwala upewnić się, że po odczytaniu wartości otrzymujesz aktualną wartość, a nie buforowaną wartość, która właśnie stała się nieaktualna przez zapis w innym wątku.
źródło
Istnieją dwa różne zastosowania niestabilnego słowa kluczowego.
Zajęty flaga jest stosowany w celu zapobiegania dalszemu wątku, kiedy urządzenie jest zajęte, a flaga nie jest zabezpieczone przez blokadę:
Wątek testowy będzie kontynuowany, gdy inny wątek wyłączy flagę zajętości :
Ponieważ jednak zajęty jest często uzyskiwany w wątku testowym, JVM może zoptymalizować test poprzez umieszczenie wartości zajętości w rejestrze, a następnie przetestować zawartość rejestru bez odczytywania wartości zajętości w pamięci przed każdym testem. Wątek testowy nigdy nie zobaczy zmiany zajętości, a drugi wątek zmieni tylko wartość zajętości w pamięci, co spowoduje zakleszczenie. Deklaracja flagi zajętości jako lotnej wymusza odczytanie jej wartości przed każdym testem.
Zastosowanie zmiennych niestabilnych zmniejsza ryzyko błędów spójności pamięci , ponieważ każdy zapis do zmiennej niestabilnej ustanawia relację „dzieje się przed” z kolejnymi odczytami tej samej zmiennej. Oznacza to, że zmiany zmiennej lotnej są zawsze widoczne dla innych wątków.
Technika czytania, pisania bez błędów spójności pamięci nazywa się działaniem atomowym .
Działanie atomowe to takie, które skutecznie dzieje się jednocześnie. Działanie atomowe nie może zatrzymać się w środku: albo dzieje się całkowicie, albo wcale. Żadne skutki uboczne akcji atomowej nie są widoczne, dopóki akcja nie zostanie zakończona.
Poniżej znajdują się działania, które możesz określić, które są atomowe:
Twoje zdrowie!
źródło
volatile
mówi dla programisty, że wartość zawsze będzie aktualna. Problem polega na tym, że wartość można zapisać w różnych typach pamięci sprzętowej. Mogą to być na przykład rejestry procesora, pamięć podręczna procesora, pamięć RAM ... Rejestry СPU i pamięć podręczna procesora należą do procesora i nie mogą współużytkować danych w przeciwieństwie do pamięci RAM, która jest ratowana w środowisku wielowątkowymvolatile
Hasło mówi, że zmienna będzie odczytywane i zapisywane z / do pamięci RAM bezpośrednio . Ma pewien ślad obliczeniowyJava 5
rozszerzonevolatile
poprzez wsparcie [O firmiehappens-before
]volatile
Hasło nie leczy sięrace condition
sytuację, kiedy kilka wątków można napisać kilka wartości jednocześnie. Odpowiedzią jestsynchronized
słowo kluczowe [Informacje]W rezultacie jest to bezpieczne tylko wtedy, gdy jeden wątek pisze, a inne po prostu odczytują
volatile
wartośćlotny vs zsynchronizowany
źródło
Volatile wykonuje następujące czynności.
1> Odczytywanie i zapisywanie zmiennych lotnych przez różne wątki są zawsze z pamięci, a nie z własnej pamięci podręcznej wątku lub rejestru procesora. Dlatego każdy wątek zawsze dotyczy najnowszej wartości. 2> Gdy 2 różne wątki działają z tą samą instancją lub zmiennymi statycznymi w stercie, działania innych mogą być postrzegane jako nieuporządkowane. Zobacz blog Jeremy'ego Mansona na ten temat. Ale niestabilność pomaga tutaj.
Poniższy w pełni działający kod pokazuje, jak wiele wątków może być wykonywanych w predefiniowanej kolejności i drukowanych wydrukach bez użycia synchronizowanego słowa kluczowego.
Aby to osiągnąć, możemy użyć następującego pełnego kodu uruchomionego.
Poniższy link do github zawiera plik readme, który daje właściwe wyjaśnienie. https://github.com/sankar4git/volatile_thread_ordering
źródło
Na stronie dokumentacji wyroczni pojawia się potrzeba zmiennej zmiennej, aby naprawić problemy z spójnością pamięci:
Oznacza to, że zmiany w
volatile
zmiennej są zawsze widoczne dla innych wątków. Oznacza to również, że gdy wątek odczytuje zmienną zmienną, widzi nie tylko ostatnią zmianę wvolatile
, ale także skutki uboczne kodu, który doprowadził do zmiany.Jak wyjaśniono w
Peter Parker
odpowiedzi, przy brakuvolatile
modyfikatora stos każdego wątku może mieć własną kopię zmiennej. Dokonując zmiennej jakovolatile
naprawiono problemy ze spójnością pamięci.Zajrzyj na stronę samouczka z jenkovem dla lepszego zrozumienia.
Spójrz na powiązane pytanie SE, aby uzyskać więcej informacji na temat niestabilnych i przypadków użycia, aby używać niestabilnych:
Różnica między zmienną i zsynchronizowaną w Javie
Jeden praktyczny przypadek użycia:
Masz wiele wątków, które trzeba wydrukować aktualny czas w określonym formacie, na przykład:
java.text.SimpleDateFormat("HH-mm-ss")
. Yon może mieć jedną klasę, która konwertuje aktualny czasSimpleDateFormat
i aktualizuje zmienną co sekundę. Wszystkie inne wątki mogą po prostu używać tej zmiennej zmiennej do drukowania bieżącego czasu w plikach dziennika.źródło
Zmienne lotne to lekka synchronizacja. Gdy wymagana jest widoczność najnowszych danych wśród wszystkich wątków, a atomowość może być zagrożona, w takich sytuacjach należy preferować Zmienne Zmienne. Odczytywanie zmiennych zmiennych zawsze zwraca ostatni zapis wykonany przez dowolny wątek, ponieważ nie są one buforowane w rejestrach ani w pamięciach podręcznych, w których inne procesory nie widzą. Volatile jest bez blokady. Używam lotnych, gdy scenariusz spełnia kryteria, jak wspomniano powyżej.
źródło
Klucz niestabilny, gdy jest używany ze zmienną, zapewni, że wątki czytające tę zmienną zobaczą tę samą wartość. Teraz, jeśli masz wiele wątków odczytujących i zapisujących zmienną, zmienność zmiennej nie będzie wystarczająca, a dane zostaną uszkodzone. Wątki obrazów odczytały tę samą wartość, ale każdy z nich wykonał pewne operacje (powiedzmy, że zwiększył licznik), podczas zapisywania w pamięci naruszana jest integralność danych. Dlatego konieczne jest zsynchronizowanie zmiennego (możliwe są różne sposoby)
Jeśli zmiany są wykonywane przez 1 wątek, a pozostałe muszą tylko odczytać tę wartość, niestabilność będzie odpowiednia.
źródło
Zmienna niestabilna jest zasadniczo używana do natychmiastowej aktualizacji (opróżniania) w głównej linii współdzielonej pamięci podręcznej po jej aktualizacji, dzięki czemu zmiany są natychmiast odzwierciedlane we wszystkich wątkach roboczych.
źródło
Poniżej znajduje się bardzo prosty kod, który demonstruje wymaganie
volatile
zmiennej, która jest używana do kontrolowania wykonywania wątku z innego wątku (jest to jeden scenariusz, w którymvolatile
jest wymagany).Gdy
volatile
nie jest używany: nigdy nie zobaczysz komunikatu „ Zatrzymano w: xxx ” nawet po „ Zatrzymanie w: xxx ”, a program będzie nadal działać.Po
volatile
użyciu: natychmiast zobaczysz komunikat „ Zatrzymano: xxx ”.Demo: https://repl.it/repls/SilverAgonizingObjectcode
źródło