W Javie 8 mogę łatwo napisać:
interface Interface1 {
default void method1() {
synchronized (this) {
// Something
}
}
static void method2() {
synchronized (Interface1.class) {
// Something
}
}
}
Otrzymam pełną semantykę synchronizacji, której mogę używać także na zajęciach. Nie mogę jednak użyć synchronized
modyfikatora do deklaracji metod:
interface Interface2 {
default synchronized void method1() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
static synchronized void method2() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
}
Teraz, można argumentować, że te dwa interfejsy zachowują się tak samo, z wyjątkiem, że Interface2
ustanawia umowę w sprawie method1()
oraz w sprawie method2()
, która jest nieco silniejsze niż to, co Interface1
robi. Oczywiście możemy również argumentować, że default
implementacje nie powinny przyjmować żadnych założeń dotyczących konkretnego stanu implementacji lub że takie słowo kluczowe po prostu nie zwiększy jego wagi.
Pytanie:
Jaki jest powód, dla którego grupa ekspertów JSR-335 postanowiła nie obsługiwać synchronized
metod interfejsu?
java
java-8
synchronized
default-method
jsr335
Lukas Eder
źródło
źródło
default synchronized
, ale niekoniecznie dlastatic synchronized
, chociaż zgodziłbym się, że ten drugi mógł zostać pominięty ze względów spójności.synchronized
modyfikator może zostać zastąpiony w podklasach, dlatego miałoby to znaczenie tylko wtedy, gdyby istniało coś jako ostateczne domyślne metody. (Twoje drugie pytanie)synchronized
w superklasach, skutecznie usuwając synchronizację. Nie zdziwiłbym się jednak, że brak wsparciasynchronized
i brak wsparciafinal
jest powiązany, być może z powodu wielokrotnego dziedziczenia (np. Dziedziczenievoid x()
isynchronized void x()
itp.). Ale to spekulacje. Jestem ciekawy wiarygodnego powodu, jeśli taki istnieje.super
co wymaga pełnej ponownej implementacji i możliwego dostępu do członków prywatnych. Poza tym istnieje powód, dla którego metody te nazywane są „obrońcami” - są one obecne, aby umożliwić łatwiejsze dodawanie nowych metod.Odpowiedzi:
Choć na początku może wydawać się oczywiste, że ktoś chciałby obsługiwać
synchronized
modyfikator w metodach domyślnych, okazuje się, że takie postępowanie byłoby niebezpieczne i dlatego było zabronione.Metody zsynchronizowane są skrótem dla metody, która zachowuje się tak, jakby całe ciało było zamknięte w
synchronized
bloku, którego obiektem blokady jest odbiornik. Rozsądne może być rozszerzenie tej semantyki na metody domyślne; w końcu są to również metody instancji z odbiornikiem. (Zauważ, żesynchronized
metody są całkowicie optymalizacją składniową; nie są potrzebne, są po prostu bardziej zwarte niż odpowiednisynchronized
blok. Należy uzasadnić argument, że była to przede wszystkim przedwczesna optymalizacja składniowa i że metody synchronizowane powodują więcej problemów niż rozwiązują, ale ten statek płynął dawno temu.)Dlaczego są niebezpieczne? Synchronizacja polega na blokowaniu. Blokowanie polega na koordynowaniu wspólnego dostępu do stanu zmiennego. Każdy obiekt powinien mieć strategię synchronizacji, która określa, które blokady chronią zmienne stanu. (Zobacz Współbieżność Java w praktyce , sekcja 2.4.)
Wiele obiektów stosuje jako swoją strategię synchronizacji wzorzec monitorowania Java (JCiP 4.1), w którym stan obiektu jest chroniony przez jego wewnętrzną blokadę. W tym wzorze nie ma nic magicznego ani specjalnego, ale jest to wygodne, a użycie
synchronized
słowa kluczowego w metodach domyślnie zakłada ten wzór.Jest to klasa, która jest właścicielem stanu, który może określić zasady synchronizacji tego obiektu. Ale interfejsy nie są właścicielami stanu obiektów, w które się wmieszają. Zatem użycie metody synchronicznej w interfejsie zakłada określoną zasadę synchronizacji, ale taką, na którą nie masz uzasadnionych podstaw, więc może się zdarzyć, że użycie synchronizacji nie zapewnia żadnego dodatkowego bezpieczeństwa wątku (być może synchronizacja odbywa się na niewłaściwej blokadzie). To dałoby fałszywe poczucie pewności, że zrobiłeś coś z bezpieczeństwem wątków, a żaden komunikat o błędzie nie mówi, że zakładasz niewłaściwą politykę synchronizacji.
Jest już wystarczająco trudne, aby konsekwentnie utrzymywać zasady synchronizacji dla jednego pliku źródłowego; jeszcze trudniej jest upewnić się, że podklasa poprawnie przestrzega zasad synchronizacji określonych przez jej nadklasę. Próba zrobienia tego między takimi luźno powiązanymi klasami (interfejs i prawdopodobnie wiele klas, które go implementują) byłaby prawie niemożliwa i bardzo podatna na błędy.
Biorąc pod uwagę wszystkie te argumenty przeciwko, jaki byłby argument? Wygląda na to, że chodzi głównie o to, aby interfejsy zachowywały się bardziej jak cechy. Chociaż jest to zrozumiałe pragnienie, centrum projektowania metod domyślnych jest ewolucja interfejsu, a nie „Cechy…”. Tam, gdzie te dwa cele można było konsekwentnie osiągnąć, staraliśmy się to zrobić, ale tam, gdzie jeden jest w konflikcie z drugim, musieliśmy wybrać główny cel projektowania.
źródło
synchronized
modyfikator metody pojawił się w wyjściu javadoc, wprowadzając ludzi w błąd, myśląc, że jest to część specyfikacji. Zostało to naprawione w JDK 1.2. Nawet jeśli pojawia się w metodzie publicznej,synchronized
modyfikator jest częścią implementacji, a nie kontraktu. (Podobne uzasadnienie i leczenie miały miejsce w przypadkunative
modyfikatora).synchronized
elementów bezpiecznych dla wątków, a program miał prawie wątkowy. Problem polegał na tym, że zwykle działało to dobrze, ale pękało w zaskakujący i kruchy sposób. Zgadzam się, że zrozumienie, jak działa blokowanie, jest kluczem do niezawodnych aplikacji.synchronized(this) {...}
dozwolonadefault
? (Jak pokazano w pytaniu Lukasa). Czy to nie pozwala, aby domyślna metoda była również właścicielem stanu klasy implementacji? Czy my też nie chcemy temu zapobiec? Czy potrzebujemy reguły FindBugs, aby znaleźć przypadki, w których robią to niedoinformowani programiści?synchronized(vector)
. Jeśli chcesz być bezpieczny, nigdy nie powinieneś używać obiektu publicznego (takiego jak onthis
sam) do blokowania.wynik:
(przepraszam za użycie klasy nadrzędnej jako przykładu)
z tego wynika, że blokada klasy nadrzędnej jest własnością każdej podklasy, SonSync1 i obiekt SonSync2 mają inną blokadę obiektu. każdy zamek jest niezależny. więc w tym przypadku myślę, że używanie synchronizacji w klasie nadrzędnej lub wspólnego interfejsu nie jest niebezpieczne. czy ktoś mógłby wyjaśnić więcej na ten temat?
źródło