[Java] "notifyAll" nie budzi funkcji z "wait"


(Sdobroc) #1

Witam

Na początek może przedstawię swój kawałek kodu, którego dotyczy problem, a potem będę wyjaśniał :wink:

synchronized void wyswietl_(Uchwyt ap, char ch)

    {  

        if (serwer.liczniku>0)

            try{

                ap.getTytul_ksiazki().wait();

               } 

            catch(InterruptedException e) { System.out.println("Wyjatek czekania funkcji wyswietlania "+e);}

        serwer.licznikw++;

        ap.Funkcje_wyswietlania(ch);

        serwer.licznikw--;

        if (serwer.licznikw==0) {

            ap.getTytul_ksiazki().notifyAll();

        }

    }


    synchronized void usun_(Uchwyt ap, char ch)

    {

        if (serwer.licznikw>0)

        {

            try{

                ap.getTytul_ksiazki().wait();

               } 

            catch(InterruptedException e) { System.out.println("Wyjatek czekania funkcji wyswietlania "+e);}

        }

        serwer.liczniku++;

        ap.Funckje_usuwania(ch);

        serwer.liczniku--;

        if (serwer.liczniku==0) {

            ap.getTytul_ksiazki().notifyAll();

        }

    }

A teraz o co chodzi - załączone dwie funkcje są metodami klasy komponent_serwera (Socket), która współdziała z klasą główny_serwer (SocketServer) i "rozmawia" z klientem (Socket). "Główny_serwer" jest tutaj pośrednikiem i pilnuje, żeby każdy wywołany klient miał własny komponent_serwera (tworzy go jako nowy wątek).

Idea całego programu to dać możliwość kilku klientom używania wspólnego zasobu, jakim jest w tym wypadku kolekcja "Uchwyt" (jest to klasa z własnymi metodami wyświetlania, dodawania, usuwania itp. objektów typu "Książka").

O co chodzi z tymi dwoma funkcjami - ano o to, że w moim zadaniu jest dodatkowy warunek: dwóch różnych klientów nie może naraz usuwać i wyświetlać książek z "Uchwytu". Nie i już :stuck_out_tongue:

Więc zrobiłem te dwie funkcje, które mają za zadanie sprawdzić czy klient który podał odpowiedni "char ch" może dostąpić zaszczytu wyświetlenia/usunięcia książek. W tym celu sprawdzany jest serwer.liczniku (licznik usunięć) lub serwer.licznikw (licznik wyświetleń) - ideą działania tych liczników jest to, że jeśli licznik usunięć jest równy zero (żaden klient nic nie usuwa) to można bezpiecznie wyświetlać dane i vice versa dla licznika wyświetleń.

Problem polega na tym, że jeśli już jakaś funkcja uśpi wątek (a bo klient chce coś usunąć, a ktoś inny wyświetla i poprawnie blokowany jest dostęp) to już się nie budzi - kiedy ktoś inny skończy wyświetlać dane i "notifyAll" się wykona, to z jakiegoś powodu nie budzi poprzedniego wątku żeby ten mógł sobie spokojnie coś usunąć.

Teraz mogłoby powstać pytanie - czy aby napewno "notyfiAll" się wykonuje wtedy kiedy ma się wykonać? Otóż jak najbardziej - sprawdziłem to poprzez dodanie wiadomości tekstowej tuż obok niego (wewnątrz jego własnego "if") i jestem pewien że się wykonuje.

ap.getTytul_ksiazki() to wywołanie kolekcji z obiektu "Uchwyt" - chciałem mieć w ten sposób pewność że "wait" i "notifyAll" wykonują się dla tego samego obiektu (kolekcji). Niestety nic to nie zmieniło.

Z góry dziękuję i czekam na jakiś odzew :slight_smile:


(Spam) #2

Nie należy synchronizować po typie String (String nie jest mutable). Możesz za to sychronizować po typie Object, który działałby jak strażnik dla String:

http://docs.oracle.com/javase/tutorial/ ... ksync.html


(Sdobroc) #3

Łał, nie sądziłem że rozwiązanie może być takie proste. Wielkie dzięki! :smiley: