2012-05-01 12 views
5

Czy to możliwe, że notify() w innym wątku zostanie wywołane przed wait() w jednym wątku? To się ze mną dzieje.Java notify() zostaje wywołana przed wait()

Klient żąda wartości od celu i czeka na zmienną wyników RV. Jeśli celem jest sam klient, aktualizuję RV z poprawnym wynikiem i wywołuję notify() na RV w innym wątku.

class EMU { 

    ResultVar RV; 
    Address my_address; 

    ResultVar findValue(String key) { 
    String tgt = findTarget(key); 
    sendRequest(tgt, key); 
    synchronized(RV) { 
     RV.wait(); 
    } 

    return RV; 
    } 

    Runnable Server = new Runnable() { 
    public void run() { 
     //code to receive connections. Assume object of type Request is read from the stream. 
     Request r = (Request) ois.readObject(); 
     if(r.requesterAddr.compareTo(my_address) == 0) { 
     String val = findVal(key); 
     RV.putVal(val); 
     synchronized(RV){ 
      RV.notify(); 
     } 
     } 
    } 
    }; 
} 

Problem polega na tym, że przed wnioskodawca ukończył wszystkie „sieci” (sendReqest w powyższym przykładzie) ze sobą, wynik jest aktualizowany w zmiennej wynikowej. Gdy wątek requestera wywoła funkcję wait(), program nie będzie kontynuowany, ponieważ powiadomienie zostało już wywołane.

Jak możemy temu zapobiec?

+1

'W przypadku, gdy celem jest klient itself' Co masz na myśli tutaj? Czy możesz umieścić próbkę kodu? – Cratylus

+1

@shishir garg czy możesz wkleić kod –

+0

Nie widząc kodu trudno jest odpowiedzieć - 2 komentarze jednak: a) ogólnie lepiej jest użyć powiadomienia zamiast powiadamiać, chyba że wiesz co robisz b) używając wait i powiadomienie może być podatne na błędy i powinieneś używać interfejsu API wyższego poziomu, chyba że potrzebujesz czegoś bardzo specyficznego. – assylias

Odpowiedz

4

Nic nie zatrzyma dzwonisz notify na obiekcie, który nie jest będącego wait ed przez inny wątek.

Wygląda na to, że to, czego oczekujesz, to oczekiwanie tylko wtedy, gdy spełniony jest jakiś warunek. Na przykład:

synchronized (results) { 
    while (!results.hasResults()) { 
     // no results yet; wait for them 
     try { 
      results.wait(); 
     } catch (InterruptedException ie) { /* ignore */ } 
    } 
} 
1

Zdecydowanie nie polecam ponownego wynajdywania koła.

Interfejs Javy Future jest przeznaczony do wyświetlania wyników, które mogą pojawić się dopiero później, a klasa FutureTask implementuje ten interfejs.

Zdobądź pierwszy wątek, aby uzyskać dostęp do Przyszłości i zdobądź drugi wątek, aby uruchomić FutureTask, a wszystkie te rzeczy zostaną załatwione za Ciebie. Otrzymasz także wsparcie czasowe za darmo.

0

korzystać z niektórych warunek przed pójściem do wait() i upewnij się, że warunek ten jest bezpieczny wątek :)

class EMU{ 
    ResultVar RV; 
    Address my_address; 
    volatile boolean condition = true; 

    ResultVar findValue(String key){ 
     String tgt = findTarget(key); 
     sendRequest(tgt, key); 
     synchronized(RV){ 
      while(condition == true) 
      { 
       RV.wait(); 
      } 
     } 
     return RV; 
    } 

    Runnable Server = new Runnable(){ 
     public void run(){ 
      //code to receive connections. Assume object of type Request is read from the stream. 
      Request r = (Request) ois.readObject(); 
      if(r.requesterAddr.compareTo(my_address) == 0){ 
       String val = findVal(key); 
       RV.putVal(val); 
       synchronized(RV){ 
        condition = false; 
        RV.notify(); 
       } 
      } 
     } 

    }; 
Powiązane problemy