programowanieBackend developer

Co to jest zmienna 'volatile' w Javie i jak różni się od 'synchronized'? Kiedy i dlaczego używać volatile?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

volatile to modyfikator zmiennej, który zapewnia widoczność zmian tej zmiennej dla wszystkich wątków. Jeśli zmienna jest zadeklarowana jako volatile, to jej odczyt i zapis odbywają się bezpośrednio z pamięci głównej, omijając lokalne pamięci podręczne wątków. Zapobiega to lokalnemu buforowaniu wartości w wątku.

synchronized to słowo kluczowe, które zapewnia nie tylko widoczność, ale także wzajemne wykluczenie (mutual exclusion): tylko jeden wątek może wykonywać zsynchronizowany blok w danym momencie dla danego obiektu.

Zmiennych volatile należy używać dla prostych flag i liczników, jeśli:

  • wartość zmiennej nie zależy od poprzedniego stanu (np. licznik jest zapisywany tylko raz, a odczytywany wiele razy);
  • nie ma potrzeby przeprowadzania bardziej skomplikowanej sekwencji operacji (check-then-act).

Przykład użycia zmiennej volatile:

class Flag { private volatile boolean running = true; public void stop() { running = false; } public void loop() { while (running) { // ... } } }

Pytanie z podstępem

Czy można używać volatile do zapewnienia atomowości inkrementacji zmiennej?

Odpowiedź: Nie, volatile nie zapewnia atomowości operacji. Na przykład, counter++ nie jest operacją atomową, nawet jeśli counter jest zadeklarowany jako volatile, ponieważ operacja obejmuje odczyt, modyfikację i zapis (wiele działań), które mogą być przerwane przez inny wątek. Atomowość zapewnia synchronizacja lub klasy z pakietu java.util.concurrent.atomic.

Przykład:

class Counter { private volatile int count = 0; public void increment() { count++; // NIE atomowa operacja! } }

Przykłady rzeczywistych błędów z powodu niewiedzy na temat tematu


Historia

W projekcie sklepu internetowego flaga zakończenia wątku przetwarzania zamówień była implementowana bez volatile. W wyniku tego jeden z wątków „zawiesił się” w nieskończonej pętli, ponieważ nie widział zmiany zmiennej dokonanej przez inny wątek. Diagnostyka zajęła kilka dni.


Historia

W systemie finansowym programista użył volatile int do licznika operacji. W szczytowych obciążeniach liczba operacji zaczynała „znikać”. Przyczyna - utrata atomowości podczas złożonych operacji inkrementacji.


Historia

Programiści pomylili volatile i synchronized, próbując użyć volatile do zapewnienia wzajemnego wykluczenia dostępu do sekcji krytycznych, co doprowadziło do wyścigu danych i trudnych do wychwycenia błędów w aplikacji wielowątkowej.