Szukałem bardziej szczegółowej odpowiedzi na: „jakie są ograniczenia każdego z nich?”. Na przykład, jeśli jest flagą ustawioną przez jeden wątek i odczytaną przez jeden lub więcej innych, nie ma potrzeby użycia AtomicBoolean. Jednak, jak widzę z tymi odpowiedziami, jeśli wątek współużytkuje zmienną w wielu wątkach, które mogą pisać i działają na podstawie wyników ich odczytów, AtomicBoolean wprowadza operacje nieblokujące typu CAS. Właściwie uczę się tutaj sporo. Mamy nadzieję, że inni również skorzystają.
lotna wartość logiczna będzie wymagała wyraźnej synchronizacji, aby poradzić sobie z warunkami wyścigu, innymi słowy, scenariusz taki jak aktualizacja zasobu współdzielonego (zmiana stanu) przez wiele wątków, np. licznik przyrostu / zmniejszenia lub zmiana wartości logicznej.
Po prostu są zupełnie inne. Rozważ ten przykład liczby volatilecałkowitej:
volatileint i =0;void incIBy5(){
i +=5;}
Jeśli dwa wątki wywołują funkcję jednocześnie, imoże to być później 5, ponieważ skompilowany kod będzie nieco podobny do tego (z tym wyjątkiem, że nie można zsynchronizować int):
void incIBy5(){int temp;synchronized(i){ temp = i }synchronized(i){ i = temp +5}}
Jeśli zmienna jest lotna, każdy dostęp atomowy do niej jest synchronizowany, ale nie zawsze jest oczywiste, co tak naprawdę kwalifikuje się jako dostęp atomowy. W przypadku Atomic*obiektu gwarantuje się, że każda metoda jest „atomowa”.
Tak więc, jeśli użyjesz AtomicIntegeri getAndAdd(int delta), możesz być pewien, że wynik będzie 10. W ten sam sposób, jeśli oba wątki jednocześnie negują booleanzmienną, AtomicBooleanmożesz być pewien, że później będzie miała oryginalną wartość, a nie volatile boolean, możesz.
Więc jeśli masz więcej niż jeden wątek modyfikujący pole, musisz uczynić je atomowym lub użyć jawnej synchronizacji.
Jeśli wątek jest uruchomiony, loop()a inny wątek go wywołuje stop(), możesz wpaść w nieskończoną pętlę, jeśli go opuścisz volatile, ponieważ pierwszy wątek może buforować wartość stop. Tutaj volatilesłuży jako wskazówka dla kompilatora, aby był nieco bardziej ostrożny przy optymalizacji.
-1: podajesz przykłady, ale tak naprawdę nie wyjaśniasz różnicy między lotną a Atomicxxxx.
Jason S
70
Pytanie nie dotyczy volatile. Pytanie jest o volatile booleanvs AtomicBoolean.
dolmen
26
-1: pytanie konkretnie zadane o wartości logicznej, która jest wyjątkowym przypadkiem w porównaniu z innymi typami danych i powinna zostać wyjaśniona bezpośrednio.
John Haager
8
@ sgp15 Ma to związek z synchronizacją od wersji Java 5.
Man of One Way
6
Jeśli wartość logiczna jest odczytywana przez wiele wątków, ale zapisywana tylko przez jeden wątek, volatile booleanto wystarczy. Jeśli jest też wielu pisarzy, możesz potrzebować AtomicBoolean.
StvnBrkdll
263
Używam zmiennych ulotnych, gdy wspomniane pole jest AKTUALIZOWANE TYLKO przez jego wątek właściciela, a wartość jest odczytywana tylko przez inne wątki, możesz myśleć o tym jak o scenariuszu publikowania / subskrypcji, w którym jest wielu obserwatorów, ale tylko jeden wydawca. Jeśli jednak ci obserwatorzy muszą wykonać jakąś logikę na podstawie wartości pola, a następnie wypchnąć nową wartość, idę z atomowymi * zmiennymi lub blokadami lub zsynchronizowanymi blokami, cokolwiek najbardziej mi odpowiada. W wielu współbieżnych scenariuszach sprowadza się do uzyskania wartości, porównania jej z inną i aktualizacji, jeśli to konieczne, stąd metody CompareAndSet i getAndSet obecne w klasach Atomic *.
Sprawdź JavaDocs pakietu java.util.concurrent.atomic , aby uzyskać listę klas Atomic i doskonałe wyjaśnienie ich działania (właśnie dowiedziałem się, że nie zawierają blokad, więc mają przewagę nad blokadami lub blokami synchronicznymi)
To prawda, ale czy nie byłoby to dość rzadkim wymogiem dla wartości logicznej?
Robin
1
@ Robin zastanawia się nad użyciem go do kontrolowania leniwego wywołania metody inicjalizacji.
Ustaman Sangat
Myślę, że to jeden z głównych przypadków użycia.
fool4jesus
42
AtomicBooleanma metody, które wykonują swoje złożone operacje atomowo i bez konieczności używania synchronizedbloku. Z drugiej strony volatile booleanmoże wykonywać operacje złożone tylko wtedy, gdy jest to wykonywane w synchronizedbloku.
Efekty pamięciowe odczytu / zapisu volatile booleansą identyczne odpowiednio z metodami geti .setAtomicBoolean
Na przykład compareAndSetmetoda atomowo wykona następujące czynności (bez synchronizedbloku):
if(value == expectedValue){
value = newValue;returntrue;}else{returnfalse;}
Dlatego compareAndSetmetoda pozwoli Ci napisać kod, który gwarantuje wykonanie tylko raz, nawet jeśli zostanie wywołany z wielu wątków. Na przykład:
volatilesłowo kluczowe gwarantuje wcześniejszą relację między wątkami współdzielącymi tę zmienną. Nie gwarantuje to, że 2 lub więcej wątków nie będzie sobie przeszkadzać podczas uzyskiwania dostępu do tej zmiennej boolowskiej.
Dostęp boolowski (jak w typie pierwotnym) w Javie jest atomowy. Zarówno czyta, jak i zadania. Więc żaden inny wątek nie „przerwie” operacji boolowskich.
Maciej Biłas
1
Przepraszam, ale jak to odpowiada na pytanie? Atomic*Klasa okłady volatilepole.
Gray,
Czy pamięci podręczne procesora nie są głównym czynnikiem powodującym niestabilność? Aby upewnić się, że odczytana wartość jest faktycznie tym, co zostało ostatnio ustawione
żartuje
8
Volatile boolean vs AtomicBoolean
Klasy Atomic * zawijają lotną prymityw tego samego typu. Ze źródła:
publicclassAtomicLongextendsNumberimplements java.io.Serializable{...privatevolatilelong value;...publicfinallong get(){return value;}...publicfinalvoid set(long newValue){
value = newValue;}
Więc jeśli wszystko, co robisz, to zdobywanie i ustawianie Atomowej *, równie dobrze możesz zamiast tego mieć zmienne pole.
Co robi AtomicBoolean, czego nie osiąga lotna wartość logiczna?
Klasy Atomic * oferują metody, które zapewniają bardziej zaawansowane funkcje, takie jak incrementAndGet(), compareAndSet()i inne, które implementują wiele operacji (get / increment / set, test / set) bez blokowania. Właśnie dlatego klasy Atomic * są tak potężne.
Na przykład, jeśli wiele wątków używa następującego kodu ++, będą występować warunki wyścigu, ponieważ w ++rzeczywistości jest to: pobierz, zwiększ i ustaw.
privatevolatile value;...// race conditions here
value++;
Jednak następujący kod będzie działał bezpiecznie w środowisku wielowątkowym bez blokad:
privatefinalAtomicLong value =newAtomicLong();...
value.incrementAndGet();
Należy również zauważyć, że owijanie pola niestabilnego za pomocą klasy Atomic * jest dobrym sposobem na enkapsulację krytycznego zasobu współdzielonego z punktu widzenia obiektu. Oznacza to, że programiści nie mogą sobie po prostu poradzić z polem, zakładając, że nie jest to wspólne, prawdopodobnie wprowadzając problemy z polem ++; lub inny kod wprowadzający warunki wyścigu.
Jeśli istnieje wiele wątków uzyskujących dostęp do zmiennej na poziomie klasy, każdy wątek może przechowywać kopię tej zmiennej w swojej pamięci podręcznej wątków.
Zmiana zmiennej na zmienną uniemożliwi wątkom przechowywanie kopii zmiennej w pamięci podręcznej wątków.
Zmienne atomowe są różne i umożliwiają atomową modyfikację ich wartości.
Logiczny typ prymitywny jest atomowy dla operacji zapisu i odczytu, zmienny gwarantuje zasadę „zdarza się przed”. Więc jeśli potrzebujesz prostej metody get () i set (), nie potrzebujesz AtomicBoolean.
Z drugiej strony, jeśli trzeba zaimplementować pewne sprawdzenie przed ustawieniem wartości zmiennej, np. „Jeśli prawda, to ustaw na wartość fałsz”, to musisz wykonać tę operację również atomowo, w tym przypadku użyj funkcji porównawczej i innych metod dostarczonych przez AtomicBoolean, ponieważ jeśli spróbujesz zaimplementować tę logikę przy pomocy lotnych wartości logicznych, będziesz potrzebować synchronizacji, aby mieć pewność, że wartość nie zmieniła się między get a set.
Krótkie, chrupiące i na temat. volatiledziała tylko w przypadkach, gdy wątek właściciela ma możliwość aktualizacji wartości pola, a inne wątki mogą tylko odczytać.
Chaklader Asfak Arefe
3
Jeśli masz tylko jeden wątek modyfikujący wartość logiczną, możesz użyćstop zmiennej wartości logicznej (zwykle robisz to, aby zdefiniować zmienną sprawdzaną w głównej pętli wątku).
Jeśli jednak masz wiele wątków modyfikujących wartość logiczną, powinieneś użyć AtomicBoolean. W przeciwnym razie poniższy kod nie jest bezpieczny:
boolean r =!myVolatileBoolean;
Ta operacja odbywa się w dwóch krokach:
Wartość logiczna jest odczytywana.
Wartość logiczna jest zapisywana.
Jeśli inny wątek zmodyfikuje wartość pomiędzy #1i 2#, możesz otrzymać zły wynik. AtomicBooleanmetody unikają tego problemu, wykonując kroki #1i #2atomowo.
Odpowiedzi:
Po prostu są zupełnie inne. Rozważ ten przykład liczby
volatile
całkowitej:Jeśli dwa wątki wywołują funkcję jednocześnie,
i
może to być później 5, ponieważ skompilowany kod będzie nieco podobny do tego (z tym wyjątkiem, że nie można zsynchronizowaćint
):Jeśli zmienna jest lotna, każdy dostęp atomowy do niej jest synchronizowany, ale nie zawsze jest oczywiste, co tak naprawdę kwalifikuje się jako dostęp atomowy. W przypadku
Atomic*
obiektu gwarantuje się, że każda metoda jest „atomowa”.Tak więc, jeśli użyjesz
AtomicInteger
igetAndAdd(int delta)
, możesz być pewien, że wynik będzie10
. W ten sam sposób, jeśli oba wątki jednocześnie negująboolean
zmienną,AtomicBoolean
możesz być pewien, że później będzie miała oryginalną wartość, a nievolatile boolean
, możesz.Więc jeśli masz więcej niż jeden wątek modyfikujący pole, musisz uczynić je atomowym lub użyć jawnej synchronizacji.
Cel
volatile
jest inny. Rozważ ten przykładJeśli wątek jest uruchomiony,
loop()
a inny wątek go wywołujestop()
, możesz wpaść w nieskończoną pętlę, jeśli go opuściszvolatile
, ponieważ pierwszy wątek może buforować wartość stop. Tutajvolatile
służy jako wskazówka dla kompilatora, aby był nieco bardziej ostrożny przy optymalizacji.źródło
volatile
. Pytanie jest ovolatile boolean
vsAtomicBoolean
.volatile boolean
to wystarczy. Jeśli jest też wielu pisarzy, możesz potrzebowaćAtomicBoolean
.Używam zmiennych ulotnych, gdy wspomniane pole jest AKTUALIZOWANE TYLKO przez jego wątek właściciela, a wartość jest odczytywana tylko przez inne wątki, możesz myśleć o tym jak o scenariuszu publikowania / subskrypcji, w którym jest wielu obserwatorów, ale tylko jeden wydawca. Jeśli jednak ci obserwatorzy muszą wykonać jakąś logikę na podstawie wartości pola, a następnie wypchnąć nową wartość, idę z atomowymi * zmiennymi lub blokadami lub zsynchronizowanymi blokami, cokolwiek najbardziej mi odpowiada. W wielu współbieżnych scenariuszach sprowadza się do uzyskania wartości, porównania jej z inną i aktualizacji, jeśli to konieczne, stąd metody CompareAndSet i getAndSet obecne w klasach Atomic *.
Sprawdź JavaDocs pakietu java.util.concurrent.atomic , aby uzyskać listę klas Atomic i doskonałe wyjaśnienie ich działania (właśnie dowiedziałem się, że nie zawierają blokad, więc mają przewagę nad blokadami lub blokami synchronicznymi)
źródło
boolean
var, powinniśmy wybraćvolatile boolean
.Nie można tego zrobić
compareAndSet
,getAndSet
jako operacja atomowa lotnymi Boolean (o ile oczywiście go zsynchronizować).źródło
AtomicBoolean
ma metody, które wykonują swoje złożone operacje atomowo i bez konieczności używaniasynchronized
bloku. Z drugiej stronyvolatile boolean
może wykonywać operacje złożone tylko wtedy, gdy jest to wykonywane wsynchronized
bloku.Efekty pamięciowe odczytu / zapisu
volatile boolean
są identyczne odpowiednio z metodamiget
i .set
AtomicBoolean
Na przykład
compareAndSet
metoda atomowo wykona następujące czynności (bezsynchronized
bloku):Dlatego
compareAndSet
metoda pozwoli Ci napisać kod, który gwarantuje wykonanie tylko raz, nawet jeśli zostanie wywołany z wielu wątków. Na przykład:Gwarantuje to, że powiadomi nas tylko raz (zakładając, że żaden inny wątek nie ustawia
AtomicBoolean
gofalse
ponownie po ustawieniu natrue
).źródło
volatile
słowo kluczowe gwarantuje wcześniejszą relację między wątkami współdzielącymi tę zmienną. Nie gwarantuje to, że 2 lub więcej wątków nie będzie sobie przeszkadzać podczas uzyskiwania dostępu do tej zmiennej boolowskiej.źródło
Atomic*
Klasa okładyvolatile
pole.Klasy Atomic * zawijają lotną prymityw tego samego typu. Ze źródła:
Więc jeśli wszystko, co robisz, to zdobywanie i ustawianie Atomowej *, równie dobrze możesz zamiast tego mieć zmienne pole.
Klasy Atomic * oferują metody, które zapewniają bardziej zaawansowane funkcje, takie jak
incrementAndGet()
,compareAndSet()
i inne, które implementują wiele operacji (get / increment / set, test / set) bez blokowania. Właśnie dlatego klasy Atomic * są tak potężne.Na przykład, jeśli wiele wątków używa następującego kodu
++
, będą występować warunki wyścigu, ponieważ w++
rzeczywistości jest to: pobierz, zwiększ i ustaw.Jednak następujący kod będzie działał bezpiecznie w środowisku wielowątkowym bez blokad:
Należy również zauważyć, że owijanie pola niestabilnego za pomocą klasy Atomic * jest dobrym sposobem na enkapsulację krytycznego zasobu współdzielonego z punktu widzenia obiektu. Oznacza to, że programiści nie mogą sobie po prostu poradzić z polem, zakładając, że nie jest to wspólne, prawdopodobnie wprowadzając problemy z polem ++; lub inny kod wprowadzający warunki wyścigu.
źródło
Jeśli istnieje wiele wątków uzyskujących dostęp do zmiennej na poziomie klasy, każdy wątek może przechowywać kopię tej zmiennej w swojej pamięci podręcznej wątków.
Zmiana zmiennej na zmienną uniemożliwi wątkom przechowywanie kopii zmiennej w pamięci podręcznej wątków.
Zmienne atomowe są różne i umożliwiają atomową modyfikację ich wartości.
źródło
Logiczny typ prymitywny jest atomowy dla operacji zapisu i odczytu, zmienny gwarantuje zasadę „zdarza się przed”. Więc jeśli potrzebujesz prostej metody get () i set (), nie potrzebujesz AtomicBoolean.
Z drugiej strony, jeśli trzeba zaimplementować pewne sprawdzenie przed ustawieniem wartości zmiennej, np. „Jeśli prawda, to ustaw na wartość fałsz”, to musisz wykonać tę operację również atomowo, w tym przypadku użyj funkcji porównawczej i innych metod dostarczonych przez AtomicBoolean, ponieważ jeśli spróbujesz zaimplementować tę logikę przy pomocy lotnych wartości logicznych, będziesz potrzebować synchronizacji, aby mieć pewność, że wartość nie zmieniła się między get a set.
źródło
Zapamiętaj IDIOM -
CZYTAJ - MODYFIKUJ - NAPISZ to, czego nie da się osiągnąć przy pomocy lotnych
źródło
volatile
działa tylko w przypadkach, gdy wątek właściciela ma możliwość aktualizacji wartości pola, a inne wątki mogą tylko odczytać.Jeśli masz tylko jeden wątek modyfikujący wartość logiczną, możesz użyć
stop
zmiennej wartości logicznej (zwykle robisz to, aby zdefiniować zmienną sprawdzaną w głównej pętli wątku).Jeśli jednak masz wiele wątków modyfikujących wartość logiczną, powinieneś użyć
AtomicBoolean
. W przeciwnym razie poniższy kod nie jest bezpieczny:Ta operacja odbywa się w dwóch krokach:
Jeśli inny wątek zmodyfikuje wartość pomiędzy
#1
i2#
, możesz otrzymać zły wynik.AtomicBoolean
metody unikają tego problemu, wykonując kroki#1
i#2
atomowo.źródło
Oba mają tę samą koncepcję, ale w boolean atomowy zapewni atomowość operacji w przypadku, gdy nastąpi zmiana procesora między nimi.
źródło