2013-04-05 11 views
11

Czytałem trochę kodu Java i znaleźć te funkcje:Zsynchronizowane słowo kluczowe java jest potrzebne w prymitywnej metodzie getter/setter?

synchronized void setConnected(boolean connected){ 
    this.connected = connected; 
} 

synchronized boolean isConnected(){ 
    return connected; 
} 

Zastanawiam się, czy synchronizacja ma sensu tutaj, lub po prostu autor nie rozumie potrzebę zsynchronizowanego hasła?

Przypuszczam, że synchronizacja jest tutaj bezużyteczna. Czy jestem w błędzie?

+0

zsynchronizowane modyfikator ma sens tylko, jeśli więcej niż jeden wątek będzie próbować uzyskać dostęp do zmiennej connected' '- przynajmniej to moje zrozumienie. –

+0

Proszę odnieść się do http://stackoverflow.com/questions/11459543/java-synchronized-getters-and-setters. Odpowiada na twoje pytanie i ładnie umieszcza je w szerszym kontekście. – prashant

+2

przeczytaj te Q + A http://stackoverflow.com/questions/11459543/java-synchronized-getters-and-setters – Zelldon

Odpowiedz

19

Słowo kluczowe synchronized jest jednym ze sposobów zapewnienia bezpieczeństwa wątków. Uwaga: istnieje (droga) bardziej do bezpieczeństwa wątków niż zakleszczenia lub brakujące aktualizacje z powodu dwóch wątków zwiększających int bez synchronizacji.

Rozważmy następujące klasy:

class Connection { 
    private boolean connected; 
    synchronized void setConnected(boolean connected){ 
    this.connected = connected; 
    } 
    synchronized boolean isConnected(){ 
    return connected; 
    } 
} 

Jeżeli wiele wątków dzielić instancją Connection i zwraca jeden wątek setConnected(true), bez synchronized możliwe jest, że inne wątki zachować widząc isConnected() == false. Słowo kluczowe synchronized gwarantuje, że wszystkie wątki widzą bieżącą wartość pola.

W bardziej technicznych terminach słowo kluczowe synchronized zapewnia barierę pamięci (wskazówka: google to).

Więcej szczegółów: każde zapisanie przed zwolnieniem monitora (tj. Przed opuszczeniem bloku synchronized) jest widoczne dla każdego odczytu dokonanego po uzyskaniu tego samego monitora (tj. Po wprowadzeniu bloku synchronizującego ten sam obiekt). W Javie dzieje się coś o nazwie - przed (wskazówka: google to), co nie jest tak banalne jak "Napisałem kod w tej kolejności, więc rzeczy są wykonywane w tej kolejności". Używanie metody synchronized jest sposobem na ustalenie relacji między zdarzeniami przed rozpoczęciem i zagwarantowanie, że wątki będą widzieć pamięć tak, jak można by się tego spodziewać.

Innym sposobem uzyskania takich samych gwarancji, w tym przypadku, byłoby wyeliminowanie słowa kluczowego synchronized i zaznaczenie pola volatile. Gwarancje dostarczone przez volatile są następujące: wszystkie zapisy wykonane przez wątek przed zagwarantowaniem, że lotny zapis będzie widoczny dla nici po kolejnym lotnym odczycie tego samego pola.

W końcowej nocie, w tym konkretnym przypadku może lepiej byłoby użyć pola volatile zamiast synchronized dostępowych, ponieważ te dwa podejścia zapewniają takie same gwarancje i -field podejście volatile umożliwia jednoczesne dostępy do pola z różnych wątków (co może poprawić wydajność, jeśli wersja synchronized ma zbyt wiele kontrowersji).

+0

Jednak niektórzy uważają nieco lepsze praktyki, aby zsynchronizować w końcowym zakresie, jak sugerowane przez pana Skeeta w tym wątku: http://stackoverflow.com/questions/6910807/synchronization-of-non-final-field –

+0

Moje pytanie jest może głupie, ale twój boolean nie powinien być "volatile"? – Pith

+0

@pith: nie, ponieważ wszystkie dostępy do niego (tj. Wszystkie odczyty i zapisy) są wykonywane za pomocą metod synchronizowanych. –

2

Autor prawdopodobnie zaprojektował kod z myślą o wielowątkowym podejściu. Oznacza to, że metody są zsynchronizowane i więcej niż jeden wątek nie będzie mógł uzyskać dostępu do zsynchronizowanego kodu w tym samym czasie na tej samej instancji obiektu.

7

W tym miejscu potrzebna jest synchronizacja, aby zapobiec błędom spójności pamięci, patrz http://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html. Choć w tym konkretnym przypadku volatile byłoby znacznie bardziej efektywne rozwiązanie

private volatile boolean connected; 

void setConnected(boolean connected){ 
    this.connected = connected; 
} 

boolean isConnected(){ 
    return connected; 
} 
Powiązane problemy