Zmienna vs statyczna w Javie

265

Czy słusznie jest powiedzieć, że staticoznacza to jedną kopię wartości dla wszystkich obiektów ivolatile oznacza jedną kopię wartości dla wszystkich wątków?

W każdym razie staticwartość zmiennej będzie również jedną wartością dla wszystkich wątków, więc po co mamy iść volatile?

Jothi
źródło
Oficjalne wyjaśnienie lotnych: cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
Vadzim

Odpowiedzi:

365

Zadeklarowanie zmiennej statycznej w Javie oznacza, że ​​będzie tylko jedna kopia, bez względu na to, ile obiektów klasy zostanie utworzonych. Zmienna będzie dostępna nawet bez jej Objectsutworzenia. Jednak wątki mogą mieć lokalnie buforowane wartości.

Kiedy zmienna jest lotna i niestatyczna , dla każdej będzie jedna zmienna Object. Na powierzchni wydaje się więc, że nie ma różnicy od normalnej zmiennej, ale całkowicie różni się od statycznej . Jednak nawet w przypadku Objectpól wątek może buforować lokalnie wartość zmiennej.

Oznacza to, że jeśli dwa wątki aktualizują jednocześnie zmienną tego samego obiektu, a zmienna nie jest deklarowana jako zmienna, może wystąpić przypadek, w którym jeden z wątków ma w pamięci podręcznej starą wartość.

Nawet jeśli uzyskasz dostęp do wartości statycznej przez wiele wątków, każdy wątek może mieć swoją lokalną kopię w pamięci podręcznej! Aby tego uniknąć, możesz zadeklarować zmienną jako niestabilną statycznie, co zmusi wątek do odczytu za każdym razem, gdy wartość globalna.

Jednakże lotny nie jest substytutem dla właściwej synchronizacji!
Na przykład:

private static volatile int counter = 0;

private void concurrentMethodWrong() {
  counter = counter + 5;
  //do something
  counter = counter - 5;
}

Wykonywanie concurrentMethodWrongrównolegle wiele razy może doprowadzić do końcowej wartości licznika różnej od zera!
Aby rozwiązać problem, musisz wprowadzić blokadę:

private static final Object counterLock = new Object();

private static volatile int counter = 0;

private void concurrentMethodRight() {
  synchronized (counterLock) {
    counter = counter + 5;
  }
  //do something
  synchronized (counterLock) {
    counter = counter - 5;
  }
}

Lub skorzystaj z AtomicIntegerklasy.

stivlo
źródło
7
Zmienny modyfikator gwarantuje, że każdy wątek, który odczytuje pole, zobaczy ostatnią zapisaną wartość, więc jest to konieczne, jeśli zmienna jest współużytkowana przez wiele wątków i potrzebujesz tej funkcji, zależy to od przypadku użycia.
stivlo,
5
Co to jest pamięć podręczna, gdy mówisz „lokalnie buforowane”? Pamięć podręczna procesora, pamięć podręczna JVM?
mert inan
6
@ mertinan tak, zmienna może znajdować się w pamięci podręcznej bliżej procesora lub rdzenia. Aby uzyskać więcej informacji, zobacz cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html .
stivlo,
15
„lotny” nie oznacza „jednej zmiennej na obiekt”. Czyni to brak „statycznego”. -1 za nieusunięcie tego elementarnego nieporozumienia ze strony PO.
Markiz Lorne
27
@EJP Myślałem, że zdanie „Deklarując zmienną jako zmienną, będzie istniała jedna zmienna dla każdego obiektu. Na powierzchni wydaje się, że nie ma różnicy od normalnej zmiennej” wyjaśnia, że ​​dodałem, a nie statyczny , edytuj artykuł i popraw brzmienie, aby było bardziej zrozumiałe.
stivlo,
288

Różnica między statycznym a lotnym:

Zmienna statyczna : Jeśli dwa wątki (przypuśćmy t1i t2) uzyskują dostęp do tego samego obiektu i aktualizują zmienną zadeklarowaną jako statyczną, oznacza to t1i t2może tworzyć własną lokalną kopię tego samego obiektu (w tym zmiennych statycznych) w odpowiedniej pamięci podręcznej, więc zaktualizuj wykonane przez t1zmienną statyczną w lokalnej pamięci podręcznej nie będzie odzwierciedlać zmiennej statycznej dlat2 pamięci podręcznej.

Zmienne statyczne są używane w kontekście Object, gdzie aktualizacja dokonana przez jeden obiekt odzwierciedlałaby wszystkie inne obiekty tej samej klasy, ale nie w kontekście Thread gdzie aktualizacja jednego wątku do zmiennej statycznej natychmiast odzwierciedla zmiany we wszystkich wątki (w lokalnej pamięci podręcznej).

Zmienna zmienna : jeśli dwa Wątki (przypuśćmy t1i t2) uzyskują dostęp do tego samego obiektu i aktualizują zmienną, która jest zadeklarowana jako zmienna, oznacza to t1i t2może utworzyć własną lokalną pamięć podręczną obiektu, z wyjątkiem zmiennej, która jest zadeklarowana jako zmienna . Zatem zmienna zmienna będzie miała tylko jedną kopię główną, która zostanie zaktualizowana przez różne wątki, a aktualizacja dokonana przez jeden wątek do zmiennej niestabilnej zostanie natychmiast odzwierciedlona w drugim wątku.

Som
źródło
6
Cześć @Som, Proszę mnie poprawić, jeśli się mylę. Ale czy nie uważasz, że stwierdzenie „ ale nie w kontekście wątku, w którym aktualizacja jednego wątku do zmiennej statycznej natychmiast odzwierciedla zmiany we wszystkich wątkach (w lokalnej pamięci podręcznej). ” Powinno być „, ale nie w kontekście w wątku, w którym aktualizacja jednego wątku do zmiennej statycznej <<NOT>> natychmiast odzwierciedla zmiany we wszystkich wątkach (w lokalnej pamięci podręcznej). "
Jaikrat
@Jaikrat Tak, to było dla mnie bardzo mylące. Rozumiem, że masz rację i że ta odpowiedź jest zła, jak napisano. Chciałbym również zostać poprawiony, jeśli się mylę.
stuart
@Jaikrat Wątki nie buforują zmiennych statycznych, ale odnoszą się do zaktualizowanych zmiennych statycznych.
Som
@Som Chcesz poprawić para i usunąć, ale nie w kontekście Wątku . To bardzo mylące. Dzięki
Jaikrat,
Niestety ta odpowiedź jest nieprawidłowa. W nowoczesnych procesorach nawet volatilezmienna może być współużytkowana przez różne pamięci podręczne procesorów. Nie stanowi to problemu, ponieważ pamięć podręczna negocjuje wyłączną własność linii pamięci podręcznej przed jej modyfikacją.
David Schwartz
32

Oprócz innych odpowiedzi chciałbym dodać dla niego jedno zdjęcie (zdjęcie jest łatwe do zrozumienia)

wprowadź opis zdjęcia tutaj

staticzmienne mogą być buforowane dla poszczególnych wątków. W środowisku wielowątkowym, jeśli jeden wątek modyfikuje swoje buforowane dane, może to nie odzwierciedlać innych wątków, ponieważ mają ich kopię .

volatiledeklaracja zapewnia, że ​​wątki nie buforują danych i używa tylko kopii udostępnionej .

Źródło obrazu

mrsrinivas
źródło
1
zmienne statyczne są wspólne dla obiektów w wątku? To powinno odczytywać zmienne statyczne są wspólne dla obiektów wszystkie obiekty niezależnie od wątków.
cquezel,
1
„Zmienne zmienne są wspólne dla wielu wątków (a więc także obiektów)”. Zmienna nie zmienia sposobu udostępniania zmiennych między wieloma wątkami lub obiektami. Zmienia to, w jaki sposób środowisko wykonawcze może buforować wartość.
cquezel,
1
Twój komentarz na temat zmiennych statycznych dotyczy również niestatycznych, a słowa „będą buforowane” i „nie będą odzwierciedlać” powinny prawdopodobnie zostać ponownie sformułowane „mogą być buforowane” i „mogą nie odzwierciedlać”.
cquezel,
4
Byłem bardzo zdezorientowany. to zdjęcie wyczyściło wszystkie moje pytania!
vins
5

Myślę statici volatilewcale nie mam związku. Sugeruję przeczytanie samouczka Java, aby zrozumieć dostęp atomowy i dlaczego korzystać z dostępu atomowego, zrozumieć, co jest przeplatane , znajdziesz odpowiedź.

Amitabha
źródło
4

W prostych słowach,

  1. static : staticzmienne są powiązane z klasą , a nie z dowolnym obiektem . Każde wystąpienie klasy dzieli zmienną klasy, która znajduje się w jednym ustalonym miejscu w pamięci

  2. lotny : to słowo kluczowe dotyczy zarówno zmiennych klas, jak i instancji .

Zastosowanie zmiennych niestabilnych zmniejsza ryzyko błędów spójności pamięci, ponieważ każdy zapis do zmiennej niestabilnej ustanawia relację przed zdarzeniem z kolejnymi odczytami tej samej zmiennej. Oznacza to, że zmiany zmiennej lotnej są zawsze widoczne dla innych wątków

Przeczytaj ten artykuł , Javin Paul aby lepiej zrozumieć zmienne zmienne.

wprowadź opis zdjęcia tutaj

W przypadku braku volatilesłowa kluczowego wartość zmiennej w stosie każdego wątku może być inna. Dokonując zmiennej jakovolatile wszystkie wątki otrzymają tę samą wartość w pamięci roboczej i uniknięto błędów spójności pamięci.

Tutaj termin variablemoże być staticzmienną (klasową) lubinstance (obiektową).

Jeśli chodzi o zapytanie:

W każdym razie wartość zmiennej statycznej będzie również jedną wartością dla wszystkich wątków, dlaczego więc mielibyśmy stosować zmienność?

Jeśli potrzebuję instancezmiennej w mojej aplikacji, nie mogę użyć staticzmiennej. Nawet w przypadkustatic zmiennej spójność nie jest gwarantowana ze względu na pamięć podręczną wątków, jak pokazano na schemacie.

Korzystanie ze volatilezmiennych zmniejsza ryzyko błędów spójności pamięci, ponieważ każdy zapis do zmiennej lotnej ustanawia relację przed zdarzeniem z kolejnymi odczytami tej samej zmiennej. Oznacza to, że zmiany zmiennej lotnej są zawsze widoczne dla innych wątków.

Co więcej, oznacza to również, że gdy wątek odczytuje zmienną zmienną, widzi nie tylko ostatnią zmianę zmiennej, ale także skutki uboczne kodu, które doprowadziły do ​​zmiany => błędy spójności pamięci są nadal możliwe przy zmiennych zmiennych . Aby uniknąć skutków ubocznych, musisz użyć zmiennych synchronizowanych. Ale java ma lepsze rozwiązanie.

Korzystanie z prostego dostępu do zmiennych atomowych jest bardziej wydajne niż uzyskiwanie dostępu do tych zmiennych za pomocą zsynchronizowanego kodu

Niektóre klasy w java.util.concurrent pakiecie udostępniają metody atomowe, które nie polegają na synchronizacji.

Więcej informacji można znaleźć w tym artykule dotyczącym kontroli współbieżności na wysokim poziomie .

W szczególności spójrz na zmienne atomowe .

Powiązane pytania SE:

Volatile Vs Atomic

Volatile boolean vs AtomicBoolean

Różnica między zmienną i zsynchronizowaną w Javie

Ravindra babu
źródło
Naprawdę doceniam tę odpowiedź. Wiedziałem, co to volatilewcześniej, ale odpowiedź ta wyjaśnia wiele dla mnie dlaczego wciąż muszą korzystać volatileze staticzmiennej.
Chaklader Asfak Arefe
lotny: to słowo kluczowe dotyczy zarówno zmiennych klas, jak i instancji. Oświadczenie, które powiedziałeś powyżej, jest nieprawidłowe w odniesieniu do klasy. tylko dwa słowa kluczowe odnoszące się do zmiennej są zmienne i przejściowe. tak niestabilna nie dotyczy klasy.
ASR
lotny ma zastosowanie do zmiennych klasowych (statycznych). Sprawdź podwójnie zablokowane linki singletonowe w google, a zobaczysz, że nie rozumiesz. stackoverflow.com/questions/18093735/…
Ravindra babu
prywatna statyczna substancja lotna jest ważną deklaracją.
Ravindra babu
0

dostęp do zmiennej wartości będzie bezpośredni z pamięci głównej. Powinien być używany tylko w środowisku wielowątkowym. zmienna statyczna zostanie załadowana jeden raz. Jeśli jest używany w środowisku jednowątkowym, nawet jeśli kopia zmiennej zostanie zaktualizowana i dostęp do niej nie zaszkodzi, ponieważ istnieje tylko jeden wątek.

Teraz, jeśli zmienna statyczna jest używana w środowisku wielowątkowym, pojawią się problemy, jeśli oczekuje się od niej pożądanego wyniku. Ponieważ każdy wątek ma swoją własną kopię, jakiekolwiek zwiększenie lub zmniejszenie zmiennej statycznej z jednego wątku może nie odzwierciedlać innego wątku.

jeśli oczekuje się pożądanych wyników od zmiennej statycznej, to użyj zmiennej lotnej ze statyczną w wielowątkowości, wtedy wszystko zostanie rozwiązane.

Aslam anwer
źródło
0

Nie jestem pewien, czy zmienne statyczne są buforowane w lokalnej pamięci wątku, czy NIE. Ale kiedy wykonałem dwa wątki (T1, T2) uzyskując dostęp do tego samego obiektu (obj) i kiedy aktualizacja dokonana przez wątek T1 do zmiennej statycznej została odzwierciedlona w T2.

użytkownik2779355
źródło
-2

Jeśli zadeklarujemy zmienną jako statyczną, będzie tylko jedna kopia zmiennej. Tak więc, ilekroć różne wątki uzyskują dostęp do tej zmiennej, będzie tylko jedna końcowa wartość dla zmiennej (ponieważ dla zmiennej przypisana jest tylko jedna lokalizacja pamięci).

Jeśli zmienna zostanie zadeklarowana jako niestabilna, wszystkie wątki będą miały własną kopię zmiennej, ale wartość zostanie pobrana z pamięci głównej, więc wartość zmiennej we wszystkich wątkach będzie taka sama.

Tak więc w obu przypadkach głównym punktem jest to, że wartość zmiennej jest taka sama we wszystkich wątkach.

Jitendra Nalwaya
źródło
15
Jeśli zmienna zostanie zadeklarowana jako zmienna, wszystkie wątki będą miały własną kopię zmiennej, ale wartość zostanie pobrana z pamięci głównej. => prawo. Tak więc wartość zmiennej we wszystkich wątkach będzie taka sama. => źle, każdy wątek użyje tej samej wartości dla tego samego obiektu, ale każdy obiekt będzie miał własną kopię.
stivlo