Odpowiedzi:
Gdy wiele wątków wymaga sprawdzenia i zmiany wartości logicznej. Na przykład:
if (!initialized) {
initialize();
initialized = true;
}
To nie jest bezpieczne dla wątków. Możesz to naprawić za pomocą AtomicBoolean
:
if (atomicInitialized.compareAndSet(false, true)) {
initialize();
}
true
kiedy initialize()
nie został ukończony. Działa to tylko wtedy, gdy inne wątki nie dbają o zakończenie initialize()
.
initialized
jest po prostu używany, aby upewnić się, że initialize()
metoda wywoła tylko jeden wątek . Oczywiście initialized
fakt, że jest to prawda, nie oznacza, że inicjalizacja zdecydowanie zakończyła się w tym przypadku, więc być może nieco inny termin byłby lepszy. Znowu zależy to od tego, do czego jest używany.
volatile boolean
samo jak AtomicBoolean
?
synchronized
bloku, w którym to przypadku nie potrzebujesz już AtomicBoolean
, tylko volatile boolean
. ( if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }
upewni się, że zadzwoni tylko jeden wątek initialize
i że wszystkie pozostałe wątki będą na niego czekać, pod warunkiem, że initialized
jest zaznaczony volatile
.)
Oto notatki (z książki Briana Goetza ), które zrobiłem, które mogą ci pomóc
Klasy AtomicXXX
zapewniają nieblokującą implementację porównania i zamiany
Korzysta ze wsparcia zapewnianego przez sprzęt (instrukcja CMPXCHG na temat Intela) Gdy wiele wątków przepływa przez Twój kod korzystający z interfejsu API współbieżności atomowej, będą one skalowane znacznie lepiej niż kod korzystający z monitorów / synchronizacji na poziomie obiektu. Ponieważ mechanizmy synchronizacji Javy powodują, że kod czeka, gdy wiele krytycznych sekcji przebiega przez wiele wątków, znaczna część czasu procesora jest poświęcana na zarządzanie samym mechanizmem synchronizacji (oczekiwanie, powiadamianie itp.). Ponieważ nowy interfejs API wykorzystuje konstrukcje sprzętowe (zmienne atomowe) oraz algorytmy oczekiwania i blokowania w celu wdrożenia bezpieczeństwa wątków, dużo więcej czasu procesora spędza się na „robieniu rzeczy” niż na zarządzaniu synchronizacją.
nie tylko oferują lepszą przepustowość, ale także zapewniają większą odporność na problemy z żywotnością, takie jak impas i inwersja priorytetów.
Istnieją dwa główne powody, dla których można użyć boolean atomowych. Po pierwsze, można go modyfikować, możesz przekazać go jako odniesienie i zmienić na przykład wartość powiązaną z samą wartością logiczną.
public final class MyThreadSafeClass{
private AtomicBoolean myBoolean = new AtomicBoolean(false);
private SomeThreadSafeObject someObject = new SomeThreadSafeObject();
public boolean doSomething(){
someObject.doSomeWork(myBoolean);
return myBoolean.get(); //will return true
}
}
oraz w klasie someObject
public final class SomeThreadSafeObject{
public void doSomeWork(AtomicBoolean b){
b.set(true);
}
}
Co ważniejsze, jego wątek jest bezpieczny i może wskazywać deweloperom utrzymującym klasę, że oczekuje się, że zmienna ta zostanie zmodyfikowana i odczytana z wielu wątków. Jeśli nie używasz AtomicBoolean, musisz zsynchronizować używaną zmienną boolowską, deklarując jej zmienność lub synchronizując odczyt i zapis pola.
AtomicBoolean
Klasa daje wartość logiczną, które można aktualizować atomowo. Użyj go, gdy masz wiele wątków uzyskujących dostęp do zmiennej boolean.
Java.util.concurrent.atomic przegląd pakiet daje dobry opis na wysokim poziomie, co zajęcia w tym pakiecie zrobić i kiedy ich używać. Poleciłbym również książkę Java Concurrency in Practice autorstwa Briana Goetza.
Fragment opisu pakietu
Pakiet java.util.concurrent.atomic opis: Mały zestaw klas, które obsługują bezpieczne dla wątków programowanie na pojedynczych zmiennych. [...]
Specyfikacje tych metod umożliwiają implementacjom stosowanie wydajnych instrukcji atomowych na poziomie maszyny, które są dostępne we współczesnych procesorach. [...]
Każda z instancji klas AtomicBoolean, AtomicInteger, AtomicLong i AtomicReference zapewnia dostęp i aktualizację pojedynczej zmiennej odpowiedniego typu. [...]
Efekty pamięci dla dostępu i aktualizacji atomów są ogólnie zgodne z regułami dla substancji lotnych:
- get ma efekty pamięciowe odczytu zmiennej lotnej.
- zbiór ma efekt pamięciowy zapisu (przypisania) zmiennej lotnej.
- SłabyCompareAndSet czyta atomowo i warunkowo zapisuje zmienną, jest uporządkowany względem innych operacji pamięci na tej zmiennej, ale poza tym działa jak zwykła nieulotna operacja pamięci.
- CompareAndSet i wszystkie inne operacje odczytu i aktualizacji, takie jak getAndIncrement, mają wpływ na pamięć zarówno odczytu, jak i zapisu zmiennych lotnych.
volatile boolean
vsAtomicBoolean
: stackoverflow.com/questions/3786825/…