Volatile Vs Atomic [duplicate]

To pytanie ma już odpowiedź tutaj:

Przeczytałem gdzieś poniżej.

Java volatile keyword doesn ' t means atomic, its common misconception że po zadeklarowaniu lotności, ++ operacja będzie atomowa, aby operacja atomic you nadal trzeba zapewnić wyłączny dostęp za pomocą synchronized Metoda lub blok w Javie.

Więc co się stanie, jeśli dwa wątki zaatakują volatile prymitywną zmienną w tym samym czasie?

Czy to oznacza, że każdy, kto go zablokuje, będzie ustawiał jego wartość jako pierwszy. A jeśli w międzyczasie pojawi się jakiś inny wątek i odczyta starą wartość, podczas gdy pierwszy wątek zmieniał swoją wartość, to czy nowy wątek nie odczyta swojej starej wartości?

Jaka jest różnica między atomowym a lotnym słowo kluczowe?

Author: AADProgramming, 2013-11-02

6 answers

Efekt słowa kluczowego volatile jest w przybliżeniu taki, że każda pojedyncza operacja odczytu lub zapisu na tej zmiennej jest atomowa.

W szczególności, operacja, która wymaga więcej niż jednego odczytu / zapisu - np. i++, która jest równoważna i = i + 1, która wykonuje jeden odczyt i jeden zapis-jest nie atomowa, ponieważ inny wątek może pisać do i Pomiędzy odczytem i zapisem.

Klasy Atomic, takie jak AtomicInteger i AtomicReference, zapewniają szerszą gamę operacji atomicznie, w szczególności increment dla AtomicInteger.

 100
Author: Louis Wasserman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-02 17:08:38

Lotne i atomowe to dwa różne pojęcia. Volatile zapewnia, że pewien, oczekiwany (pamięć) stan jest prawdziwy w różnych wątkach, podczas gdy Atomika zapewnia, że operacje na zmiennych są wykonywane atomicznie.

Weźmy następujący przykład dwóch wątków w Javie:

Wątek A:

value = 1;
done = true;

Wątek B:

if (done)
  System.out.println(value);

Zaczynając od value = 0 i done = false reguła wątku mówi nam, że nie jest zdefiniowane, czy wątek B wydrukuje wartość. wartość jest również niezdefiniowana w tym momencie! aby to wyjaśnić, musisz wiedzieć trochę o zarządzaniu pamięcią Java (które może być złożone), w skrócie: wątki mogą tworzyć lokalne kopie zmiennych, a JVM może zmienić kolejność kodu, aby go zoptymalizować, dlatego nie ma gwarancji, że powyższy kod zostanie uruchomiony dokładnie w tej kolejności. Ustawienie done na true i następnie ustawienie wartości na 1 może być możliwym wynikiem optymalizacji JIT.

volatile tylko zapewnia, że w w momencie dostępu do takiej zmiennej, nowa wartość będzie natychmiast widoczna dla wszystkich pozostałych wątków i kolejność wykonania zapewnia, że kod jest w stanie, w jakim go oczekujesz. Tak więc w przypadku powyższego kodu, zdefiniowanie done jako volatile zapewni, że za każdym razem, gdy wątek B sprawdza zmienną, będzie ona albo fałszywa, albo prawdziwa, a jeśli jest prawdziwa, to value również zostanie ustawione na 1.

Jako efekt uboczny lotnych , wartość takiej zmiennej jest ustawiany na cały wątek atomicznie(przy bardzo niewielkim koszcie szybkości wykonania). Jest to jednak ważne tylko w systemach 32-bitowych, które tzn. używają długich (64-bitowych) zmiennych (lub podobnych), w większości innych przypadków ustawienie / odczyt zmiennej jest atomic anyway. Ale jest ważna różnica między dostępem atomowym a operacją atomową. Volatile zapewnia tylko, że dostęp jest atomiczny, podczas gdy Atomika zapewnia, że operacja jest atomiczna.

Weź następujące przykład:

i = i + 1;

Bez względu na to, jak zdefiniujesz i, inny wątek odczytujący wartość po wykonaniu powyższej linii może otrzymać i, lub i + 1, ponieważ operacja Nie jest atomiczna. Jeśli drugi wątek ustawia i na inną wartość, w najgorszym przypadku mogę zostać ustawiony z powrotem na to, co było wcześniej przez wątek A, ponieważ był on właśnie w środku obliczania i + 1 na podstawie starej wartości, a następnie ustawić i ponownie na tę starą wartość + 1. Explanation:

Assume i = 0
Thread A reads i, calculates i+1, which is 1
Thread B sets i to 1000 and returns
Thread A now sets i to the result of the operation, which is i = 1

Atomiki jak Atomicinteger zapewnić, że takie operacje zdarzają się atomically. Tak więc powyższy problem nie może się zdarzyć, byłbym albo 1000 lub 1001 po zakończeniu obu wątków.

 54
Author: TwoThe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-21 07:17:48

Istnieją dwa ważne pojęcia w środowisku wielowątkowym.

  1. atomicity
  2. widoczność

Volatile eliminuje problem widoczności, ale nie radzi sobie z atomicznością. Volatile uniemożliwi kompilatorowi zmianę kolejności instrukcji, która wymaga zapisu i późniejszego odczytu zmiennej zmiennej. np. k++ Tutaj k++ nie jest pojedynczą instrukcją maszynową, a trzema instrukcjami maszynowymi.

  1. skopiuj wartość do rejestr
  2. increment it
  3. umieścić go z powrotem

Więc nawet jeśli zadeklarujesz zmienną {[4] } to nie uczyni tej operacji atomową, co oznacza, że inny wątek może zobaczyć wynik pośredni, który jest nieświeżą lub niepożądaną wartością dla innego wątku.

Ale AtomicInteger, AtomicReference są oparte na instrukcji Compare and swap . CAS ma trzy operandy: lokalizację pamięci V, na której ma działać, oczekiwaną starą wartość A i nową wartość B. CAS atomicznie aktualizuje V do nowej wartości B, ale tylko wtedy, gdy wartość w V odpowiada oczekiwanej starej wartości A; w przeciwnym razie nic nie robi. W obu przypadkach zwraca wartość aktualnie w V. Jest używany przez JVM w AtomicInteger, AtomicReference i nazywają funkcję compareAndSet(). Jeśli ta funkcja nie jest obsługiwana przez procesor bazowy, JVM implementuje ją przez spin lock.

 34
Author: Trying,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-02 19:25:11

Tak jak zaznaczono, volatile zajmuje się tylko widocznością.

Rozważmy ten fragment w środowisku równoległym:

boolean isStopped = false;
    :
    :

    while (!isStopped) {
        // do some kind of work
    }

Chodzi o to, że jakiś wątek może zmienić wartość isStopped z false na true, aby wskazać następnej pętli, że nadszedł czas, aby przestać zapętlać.

Intuicyjnie nie ma problemu. Logicznie, jeśli inny wątek uczyni isStopped równym true, pętla musi się zakończyć. Rzeczywistość jest taka, że pętla prawdopodobnie nigdy się nie skończy nawet jeśli inny wątek sprawia, że isStopped jest równe true.

Powód tego nie jest intuicyjny, ale weź pod uwagę, że nowoczesne procesory mają wiele rdzeni i że każdy rdzeń ma wiele rejestrów i wiele poziomów pamięci podręcznej, które nie są dostępne dla innych procesorów. Innymi słowy, wartości, które są buforowane w pamięci lokalnej jednego procesora są nie visisble do wątków wykonujących na innym procesorze. Tutaj leży jeden z głównych problemów współbieżności: widoczność.

Model pamięci Java nie daje żadnych gwarancji, kiedy zmiany wprowadzone do zmiennej w wątku mogą stać się widoczne dla innych wątków. Aby zagwarantować, że aktualizacje są widoczne natychmiast po ich dokonaniu, należy zsynchronizować.

Słowo kluczowe volatile jest słabą formą synchronizacji. Chociaż nie robi nic dla wzajemnego wykluczenia lub atomiczności, daje gwarancję, że zmiany wprowadzone do zmiennej w jednym wątku staną się widoczne dla innych nici, gdy tylko zostanie wykonana. Ponieważ poszczególne odczyty i zapisy do zmiennych, które nie są 8-bajtami, są atomowe w Javie, deklarowanie zmiennych volatile zapewnia łatwy mechanizm zapewniający widoczność w sytuacjach, w których nie ma innych wymagań dotyczących atomiczności lub wzajemnego wykluczenia.

 19
Author: scottb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-02 18:14:24

Używane jest słowo kluczowe volatile:

  • aby nie atomowe operacje 64-bitowe były atomowe: long i double. (wszystkie inne, prymitywne dostępy są już gwarantowane jako atomowe!)
  • aby aktualizacje zmiennych były widoczne dla innych wątków + efekty widoczności: po zapisaniu do zmiennej zmiennej, wszystkie zmienne, które są widoczne przed zapisaniem tej zmiennej, stają się widoczne dla innego wątku po przeczytaniu tej samej zmiennej zmiennej (happen-before zamówienia).

Klasy java.util.concurrent.atomic.* są, zgodnie z docs java :

Mały zestaw narzędzi z klasami, które obsługują bezpieczne wątki bez blokady programowanie na pojedynczych zmiennych. W istocie, klasy w tym pakiet rozszerza pojęcie wartości lotnych, pól i tablic elementy do tych, które również zapewniają atomową aktualizację warunkową działanie formularza:

boolean compareAndSet(expectedValue, updateValue);

Klasy atomowe są zbudowane wokół atomów compareAndSet(...) Funkcja odwzorowująca instrukcję procesora atomowego. Klasy atomowe wprowadzają happen-before porządkowanie tak, jak robią to zmienne volatile. (z jednym wyjątkiem: weakCompareAndSet(...)).

From the java docs:

Gdy wątek widzi aktualizację zmiennej atomowej spowodowaną weakCompareAndSet, nie musi widzieć aktualizacji do innych zmienne, które wystąpiły przed zestawem weakCompareAndSet.

Na twoje pytanie:

Czy to znaczy że każdy, kto się tym zajmie, będzie ustawiał najpierw jego wartość. A jeśli w międzyczasie pojawi się jakiś inny wątek i odczytuje starą wartość, gdy pierwszy wątek zmieniał jej wartość, a następnie nie nowy wątek odczyta jego starą wartość?

Niczego nie blokujesz, to, co opisujesz, jest typowym stanem rasy, który w końcu się wydarzy, jeśli wątki uzyskają dostęp do udostępnionych danych bez odpowiedniej synchronizacji. Jak już wspomniano deklarowanie zmiennej volatile w tym przypadku będzie tylko upewnij się, że inne wątki będą widzieć zmianę zmiennej (wartość nie będzie buforowana w rejestrze jakiegoś bufora, który jest widziany tylko przez jeden wątek).

Jaka jest różnica między AtomicInteger a volatile int?

AtomicInteger zapewnia operacje atomowe na int z odpowiednią synchronizacją (np. incrementAndGet(), getAndAdd(...), ...), volatile int zapewni widoczność int dla innych wątków.

 10
Author: Ortwin Angermeier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-19 10:16:32

Więc co się stanie, jeśli dwa wątki zaatakują zmienną zmienną w tym samym czasie?

Zazwyczaj każdy z nich może zwiększyć wartość. Jednak czasami, oba będą aktualizować wartość w tym samym czasie i zamiast zwiększyć o 2 razem, zarówno wątku przyrost o 1 i tylko 1 jest dodawany.

Czy to oznacza, że każdy, kto go zablokuje, będzie ustawiał jego wartość jako pierwszy.

Nie ma zamka. Po to jest synchronized.

A jeśli w międzyczasie pojawi się jakiś inny wątek i odczyta starą wartość, podczas gdy pierwszy wątek zmieniał swoją wartość, to czy nowy wątek nie odczyta swojej starej wartości?

TAK,

Jaka jest różnica między Atomic i volatile keyword?

AtomicXxxx owija lotne, więc są one w zasadzie takie same, różnica polega na tym, że zapewnia operacje wyższego poziomu, takie jak CompareAndSwap, który jest używany do implementacji przyrostu.

AtomicXxxx obsługuje również lazySet. To jest jak zmienny zestaw, ale nie opóźnia potoku czekającego na zakończenie zapisu. Może to oznaczać, że jeśli odczytasz wartość, którą po prostu piszesz, możesz zobaczyć starą wartość, ale i tak nie powinieneś tego robić. Różnica polega na tym, że ustawienie lotnej zajmuje około 5 ns, bit lazySet około 0,5 NS.

 8
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-02 18:17:04