Ważna uwaga na temat volatile
:
- Synchronizacja w Javie jest możliwe za pomocą słów kluczowych, Java
synchronized
i volatile
i zamki.
- W Javie nie możemy mieć
synchronized
zmiennej. Używanie synchronized
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.
- Jeśli zmienna nie jest współużytkowana przez wiele wątków, nie trzeba używać
volatile
słowa kluczowego.
źródło
Przykładowe użycie volatile
:
public class Singleton {
private static volatile Singleton _instance; // volatile variable
public static Singleton getInstance() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
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.
Wniosek : volatile
słowo kluczowe służy również do komunikowania zawartości pamięci między wątkami.
Przykładowe użycie bez lotnych:
public class Singleton{
private static Singleton _instance; //without volatile variable
public static Singleton getInstance(){
if(_instance == null){
synchronized(Singleton.class){
if(_instance == null) _instance = new Singleton();
}
}
return _instance;
}
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.
- Gdy lista jest aktualizowana, licznik jest zwiększany.
- Po utworzeniu an
Iterator
bieżąca wartość licznika jest osadzana w Iterator
obiekcie.
- Gdy
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.
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 .