2012-05-01 2 views
5

Возможно ли, что notify() в другом потоке вызывается перед wait() в одном потоке? Это происходит со мной.Java notify() вызывается перед wait()

Клиент запрашивает значение от цели и ждет результата переменной RV. В случае, если целью является сам клиент, я обновляю RV с правильным результатом и вызываю notify() на RV в другом потоке.

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(); 
     } 
     } 
    } 
    }; 
} 

Проблема заключается в том, что до того, как запрашивающих завершил все «сети» (sendReqest в приведенном выше примере), с самими собой, то результат будет обновлен в переменном результате. Когда поток-запросчик теперь вызывает wait(), программа не будет продолжена, так как уведомление уже вызвано.

Как мы можем предотвратить это?

+1

'В случае цель клиента itself' Что вы имеете в виду здесь? Можете ли вы поместить образец кода? – Cratylus

+1

@shishir garg не могли бы вы вставить код –

+0

Не видя кода, вам сложно ответить - 2 комментария: а) обычно лучше использовать notifyAll, а не уведомлять, если вы не знаете, что делаете b) используя wait и уведомление может быть подвержено ошибкам, и вы должны использовать API параллелизма более высокого уровня, если вам не требуется что-то очень конкретное. – assylias

ответ

4

Ничто не мешает вам вызов notify на объекте, который не будучи wait éd другим потоком.

Звучит так, как будто вы хотите подождать, только если выполнено какое-то условие. Например:

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

Я бы настоятельно рекомендовал не изобретать колесо.

Интерфейс Java Future предназначен для результатов, которые могут быть получены позднее, а класс FutureTask реализует этот интерфейс.

Попросите первый поток получить доступ к Будущему и получить второй поток для запуска FutureTask, и все это будет обработано для вас. Вы также получаете бесплатную поддержку тайм-аута.

0

Используйте некоторое условие, прежде чем ждать() и убедитесь, что состояние потокобезопасно :)

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(); 
       } 
      } 
     } 

    }; 
Смежные вопросы