"notifyAll" nie budzi uśpionej funkcji.

0

Witam

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

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ż :p
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 na pewno "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!

1
  1. Synchronizujesz się na innym obiekcie (this), niż śpisz (ap.getTytul_ksiazki()). Użyj bloku "synchronized(ap.getTytul_ksiazki()). Będzie to działać pod warunkiem, że ap.getTytul_ksiazki() się nie zmienia.
    Czy w obecnej formie nie leci wyjątek przy wait()? Nie można spać na obiekcie nie będąc właścicielem jego monitora.
  2. Pola liczniku i licznikw muszą być typu voliatile.
  3. Musisz zmienić "if (serwer.licznikX>0)" na "while (serwer.licznikX>0)"
  4. Na ap.getTytul_ksiazki() czekają zarówno wątki, które chcą czytać i usuwać.
  5. Zamiast tak kombinować użyj:
    http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReadWriteLock.html

1 użytkowników online, w tym zalogowanych: 0, gości: 1