2016-02-16 21 views
12

Dlaczego metody są umieszczane w , a nie w oddzielnej klasie?Dlaczego wait() i notify() nie należą do specjalnej klasy?

Uwaga, to pytanie nie dotyczy przeniesienia ich do klasy Thread, po prostu zastanawiam się, dlaczego nie zawierają one Object, a nie jakiejś nowej klasy Monitor.

widzę następujące wady tego pomysłu:

  • My nie będą mogli korzystać z naszych for-innego przeznaczenia pola jako monitory. Ale wydaje się to zgadzać z zasadą modułowości.
  • Metody zsynchronizowane będą teraz wymagać hakowania z wygenerowanymi ukrytymi polami (jak w zamknięciach), ponieważ this i <MyClass>.class stają się niepoprawnymi monitorami.

Dzięki temu możemy odejść 5 metod z każdego obiektu z lekkim niedolem. Albo nie?

+0

'Właśnie zastanawiam się, dlaczego oni zaśmiecają Obiekt, a nie jakąś nową klasę Monitor." - koncepcyjnie, robią to wewnętrznie, ale monitor jest unikalny dla każdego obiektu. Zobacz duplikat odpowiedzi (chociaż odnosi się do "Thread") –

+1

@biziclop Dokładnie. Kiedy Per Brinch Hansen zobaczył początkowe konstrukcje współbieżności Javy, napisał: "wyraźnie pracowałem na próżno". Wygląda na to, że zostały zapożyczone z nieprzyjemnego "uśpienia/przebudzenia" wbudowanego w UNIX. – EJP

+0

* "Abyśmy mogli odejść 5 metod z każdego obiektu z odrobiną niedoli" * AFAIK z technicznego punktu widzenia metody te istnieją tylko raz, a nie raz dla każdej instancji. – m0skit0

Odpowiedz

7

Prawdziwą odpowiedzią jest, że był to błąd, ostatecznie potwierdzony przez stworzenie klasy Condition, która robi dokładnie to, czego można się spodziewać. (Chociaż ponieważ jest to przedmiot, istnieje możliwość, że będziesz przypadkowo wywołać wait() na nim zamiast await() z zabawnych konsekwencji ...)

Oprócz rzeczy, które zostały już wymienione, wiążąc monitor do każdego pojedynczego obiektu uniemożliwia również posiadanie prawdziwie niezmiennych obiektów w Javie.

Więc można to zrobić na przykład:

class A { 
    void foo() { 
     synchronized((Integer)42) { 
     ... 
     } 
    } 
} 

class B { 
    void foo() { 
     synchronized((Integer)42) { 
      ... 
     } 
    } 
} 

Wracając tą samą całkowitą pudełkowej dla 42 za każdym razem nie powinno być problemem, jeśli obiekt był niezmienny. Ale nie jest, ma zmienny stan: swój monitor, umożliwiający taką synchronizację. Szczególnie złym jest to, że stworzyłeś muteks między dwoma fragmentami kodu, które na pierwszy rzut oka wydają się niezależne.

+0

Niezwykła odpowiedź. Chciałbym dodać dodatkowe +1 na przykład z buforowaniem Integers – Martoon

+1

@Martoon Jako ćwiczenie napisałem [parę strumieni wejściowych/wyjściowych] (http://pastebin.com/r2bKbXfE), które wykorzystują to do komunikowania się ze sobą. Naprawdę przerażające jest to, że będą działać wszędzie tam, gdzie umieścisz je na tej samej maszynie wirtualnej, na przykład w dwóch oddzielnych aplikacjach internetowych w tym samym kontenerze. – biziclop

0

Ponieważ każdy obiekt może działać jako monitor.

+0

Tak, ale pytanie brzmi: dlaczego nie mieć oddzielnej klasy. – m0skit0

0

1) Oczekiwanie na powiadomienie i powiadomienie to nie tylko zwykłe metody lub narzędzie do synchronizacji, ale więcej niż mechanizm komunikacji między dwoma wątkami w Javie. Klasa obiektu jest właściwym miejscem do udostępnienia dla każdego obiektu, jeśli ten mechanizm nie jest dostępny za pośrednictwem dowolnego słowa kluczowego Java, takiego jak synchronizacja. Pamiętaj, że zsynchronizowane i oczekujące powiadomienia są dwoma różnymi obszarami i nie mylić, że są takie same lub powiązane. Synchronizacja ma zapewniać wzajemne wykluczanie i zapewniać bezpieczeństwo wątków klasy Java, takich jak warunki wyścigu, podczas gdy oczekiwanie i powiadamianie to mechanizm komunikacji między dwoma wątkami.

2) Blokady są udostępniane dla każdego obiektu, co jest kolejnym powodem oczekiwania i powiadomienia w klasie Obiekt, a nie w klasie Wątków.

3) W Javie, aby wejść do krytycznej sekcji kodu, wątki wymagają zablokowania i czekają na blokadę, nie wiedzą, które wątki blokują, zamiast tego po prostu wiedzą, że blokada jest zatrzymana przez jakiś wątek i powinny poczekać dla blokady zamiast wiedzieć, który wątek znajduje się wewnątrz zsynchronizowanego bloku i poprosić go o zwolnienie blokady. ta analogia pasuje do czekania i powiadamiania o klasie obiektu, a nie wątku w Javie.

z dopiskiem: http://javarevisited.blogspot.in/2012/02/why-wait-notify-and-notifyall-is.html

1

Jedną z zalet jest to, że można po prostu zsynchronizować na odniesienie bez tworzenia redundantnego monitora do niego:

synchronized (myList) { 
    myList.add(0); 
} 

vs

private final Object mySpecialMonitor = new Object(); 

syncronized(mySpecialMonitor) { 
    myList.add(0); 
} 

Byłoby nie działa, jeśli cała synchronizacja była w osobnej klasie.

+0

Tak, to pierwsza niedociągnięcie, które wymieniłem. Ale myślenie w ten sposób prowadzi nas do przeniesienia 'ReentrantLock.lock()', 'unlock()', 'StringBuilder.append()', nie wiem co jeszcze, do klasy 'Object', która wydaje się nie być ładny zwrot. Chodzi mi o to, klasa 'Object' nie jest przeznaczona do specjalizacji do synchronizowania – Martoon

+2

Nie nazwałbym tego zaletą. Ponieważ bezpieczną metodą synchronizacji nie jest wykonywanie tego na publicznie widocznym obiekcie, większość czasu w końcu tworzysz dedykowany obiekt blokady w "prywatnym ostatecznym" polu. – biziclop