Jeśli mam 2 zsynchronizowane metody w tej samej klasie, ale każda ma dostęp do różnych zmiennych, czy 2 wątki mogą uzyskać dostęp do tych 2 metod jednocześnie? Czy blokada występuje na obiekcie, czy staje się tak specyficzna jak zmienne w zsynchronizowanej metodzie?
Przykład:
class X {
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
}
Czy 2 wątki mogą uzyskać dostęp do tego samego wystąpienia klasy X x.addA(
) i x.addB()
jednocześnie?
synchronized (this)
blokiem wokół ciała metody. Obiekt „this” nie zostaje zablokowany, raczej obiekt „this” jest używany jako muteks, a ciało nie może wykonywać jednocześnie z innymi sekcjami kodu również zsynchronizowanymi z „this”. Nie ma wpływu na inne pola / metody „tego”, które nie są zsynchronizowane.a
ib
były obiektami, np.Integer
S, synchronizowałeś instancje, które zastępujesz innymi obiektami podczas stosowania++
operatora.Zsynchronizowany w deklaracji metody jest cukier składniowy w tym celu:
W metodzie statycznej jest to cukier syntaktyczny:
Myślę, że gdyby projektanci Javy wiedzieli, co rozumie się teraz na temat synchronizacji, nie dodaliby cukru syntaktycznego, ponieważ najczęściej prowadzi to do złych implementacji współbieżności.
źródło
Z „Samouczków Java ™” na temat metod synchronizowanych :
Z „Samouczków Java ™” na temat synchronizowanych bloków :
(Moje podkreślenie)
Załóżmy, że masz 2 zmienne nieprzeplatające . Więc chcesz mieć dostęp do każdego z różnych wątków jednocześnie. Musisz zdefiniować blokadę nie na samej klasie obiektu, ale na klasie Object jak poniżej (przykład z drugiego łącza Oracle):
źródło
Dostęp do blokady znajduje się na obiekcie, a nie na metodzie. Które zmienne są dostępne w ramach metody, nie ma znaczenia.
Dodanie „zsynchronizowanej” do metody oznacza, że wątek uruchamiający kod musi uzyskać blokadę obiektu przed kontynuowaniem. Dodanie „zsynchronizowany statycznie” oznacza, że wątek uruchamiający kod musi uzyskać blokadę obiektu klasy przed kontynuowaniem. Alternatywnie możesz owinąć kod w taki blok:
dzięki czemu można określić obiekt, którego blokada musi zostać uzyskana.
Jeśli chcesz uniknąć blokowania obiektu zawierającego, możesz wybrać między:
źródło
Z linku do dokumentacji Oracle
Synchronizacja metod ma dwa efekty:
Zajrzyj na tę stronę dokumentacji, aby zrozumieć wewnętrzne blokady i ich zachowanie.
To odpowie na twoje pytanie: na tym samym obiekcie x nie można wywoływać x.addA () i x.addB () w tym samym czasie, gdy trwa wykonywanie jednej z metod synchronizowanych.
źródło
Jeśli masz metody, które nie są zsynchronizowane i uzyskują dostęp do zmiennych instancji i zmieniają je. W twoim przykładzie:
dowolna liczba wątków może uzyskać dostęp do tych niezsynchronizowanych metod w tym samym czasie, gdy inny wątek jest w synchronizowanej metodzie tego samego obiektu i może dokonywać zmian w zmiennych instancji. Na przykład:
Należy unikać scenariusza, w którym niezsynchronizowane metody uzyskują dostęp do zmiennych instancji i zmieniają je, w przeciwnym razie nie ma sensu używać metod synchronizowanych.
W poniższym scenariuszu:
Tylko jeden wątek może być w metodzie addA lub addB, ale jednocześnie dowolna liczba wątków może wejść do metody changeState. Żadne dwa wątki nie mogą jednocześnie wprowadzić addA i addB (z powodu blokowania na poziomie obiektu), ale jednocześnie dowolna liczba wątków może wejść do changeState.
źródło
Możesz zrobić coś takiego: W tym przypadku używasz blokady na aib, aby zsynchronizować zamiast blokady na „to”. Nie możemy użyć int, ponieważ pierwotne wartości nie mają blokad, dlatego używamy liczby całkowitej.
źródło
Tak, zablokuje inną metodę, ponieważ metoda zsynchronizowana ma zastosowanie do CAŁEGO obiektu klasy jak wskazano .... ale tak czy inaczej zablokuje wykonanie innego wątku TYLKO podczas wykonywania sumy w dowolnej metodzie, do której wejdzie metoda addA lub addB, ponieważ kiedy zakończy się ... jeden wątek uwolni obiekt, a drugi wątek uzyska dostęp do drugiej metody i tak dalej działa idealnie.
Mam na myśli, że „zsynchronizowany” jest stworzony właśnie w celu zablokowania drugiemu wątkowi dostępu do innego podczas wykonywania określonego kodu. WRESZCIE TEN KOD DZIAŁA WYGODNIE.
Na koniec, jeśli istnieją zmienne „a” i „b”, a nie tylko unikalna zmienna „a” lub jakakolwiek inna nazwa, nie ma potrzeby synchronizowania tych metod, ponieważ dostęp do innej zmiennej jest całkowicie bezpieczny (inna pamięć Lokalizacja).
Będzie również działać
źródło
Ten przykład (choć nie ładny) może zapewnić lepszy wgląd w mechanizm blokujący. Jeśli incrementA jest zsynchronizowany , a incrementB nie jest zsynchronizowany , to incrementB zostanie wykonany jak najszybciej, ale jeśli incrementB jest również zsynchronizowany , musi „poczekać” na zakończenie incrementA , zanim incrementB może wykonywać swoje zadania.
Obie metody są wywoływane w jednym wystąpieniu - obiekt, w tym przykładzie jest to: zadanie , a wątki „konkurujące” są wątkiem i głównym .
Spróbuj z „ zsynchronizowanym ” w inkrementie B i bez niego, a zobaczysz inne wyniki. Jeśli inkrement B jest również „ zsynchronizowany ”, musi poczekać na zakończenie inkrementu A (). Uruchom kilka razy w każdym wariancie.
źródło
W synchronizacji Java, jeśli wątek chce wejść do metody synchronizacji, uzyska blokadę na wszystkich zsynchronizowanych metodach tego obiektu, a nie tylko na jednej zsynchronizowanej metodzie, której używa wątek. Tak więc wątek wykonujący addA () uzyska blokadę na addA () i addB (), ponieważ oba są zsynchronizowane, więc inne wątki z tym samym obiektem nie mogą wykonać addB ().
źródło
Może to nie działać, ponieważ boksowanie i autoboksowanie z Integer na int i viceversa zależą od JVM i istnieje duże prawdopodobieństwo, że dwie różne liczby mogą zostać zaszyfrowane pod tym samym adresem, jeśli są między -128 a 127.
źródło