programowanieProgramista Backend

Jak działa mechanizm synchronized w Javie? Kiedy go stosować i jakie pułapki istnieją przy synchronizacji dostępu do zasobów?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Historia pytania:

Od momentu pojawienia się Javy, programiści spotkali się z problemem konkurencyjnego dostępu do wspólnych zasobów. W celu rozwiązania wprowadzono wysokopoziomowe prymitywy synchronizacji, z których najważniejszym jest modyfikator kluczowy synchronized.

Problem:

Bez synchronizacji w aplikacjach wielowątkowych dzielone zasoby mogą być uszkodzone: pojawia się wyścig danych (data race), a stan obiektu staje się nieprzewidywalny.

Rozwiązanie:

synchronized pozwala zorganizować monitor dla metody lub bloku kodu, zapewniając dostęp tylko jednemu wątkowi w danym momencie do sekcji krytycznej. Synchronizacja wątku może być realizowana na poziomie metody lub bloku.

Przykład blokady obiektu:

public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }

Bloki również można synchronizować:

public void safeIncrement() { synchronized(this) { count++; } }

Kluczowe cechy:

  • Synchronizacja na poziomie metody jest równoznaczna z synchronizacją na poziomie this
  • Dla metod statycznych synchronizacja odbywa się na poziomie obiektu klasy
  • Należy minimalizować obszar sekcji krytycznej

Pytania podchwytliwe.

Czym różni się synchronized-metoda od synchronized-bloku?

synchronized-metoda blokuje całą metodę dla bieżącego obiektu (this) lub klasy (jeśli metoda jest statyczna). Blok pozwala synchronizować tylko potrzebny fragment kodu i wybierać dowolny obiekt do blokady.

Czy dwa różne wątki mogą jednocześnie wejść do dwóch różnych synchronized-metod jednego obiektu?

Nie, jeśli metody są synchronizowane na tym samym monitorze (this). Jeśli używają różnych monitorów, to tak.

Czy modyfikator synchronized wpływa na widoczność zmiennych między wątkami?

Tak, wejście do synchronized-bloku resetuje pamięci podręczne wątków i aktualizuje wartości zmiennych (relacja happens-before).

Typowe błędy i antywzorce

  • Synchronizacja na zbyt "szerokim" obiekcie (na przykład na String lub obiekcie klasy)
  • Długie wykonywanie kodu wewnątrz synchronizowanego bloku
  • Mieszanie dostępu do jednego zasobu przez synchronized-bloki i niesynchronizowane fragmenty

Przykład z życia

Negatywny przypadek

Programista synchronizuje statyczne metody klasy na obiekcie instancji, co nie gwarantuje poprawności przy używaniu przez różne instancje.

Plusy:

  • Łatwa implementacja

Minusy:

  • Nieoczekiwane wyścigi danych między wątkami
  • Trudne do uchwycenia błędy

Pozytywny przypadek

Wszystkie metody, korzystające ze wspólnego zasobu, są synchronizowane na jednym obiekcie-monitorze, obszar sekcji krytycznej jest minimalny.

Plusy:

  • Wątki pracują z spójnymi danymi
  • Minimalne blokowanie

Minusy:

  • Trudniej jest utrzymać i analizować wzajemne blokady (deadlock), szczególnie przy dużej liczbie synchronizowanych obiektów