Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java notify() gets called before wait()

Isn't it possible that notify() in another thread gets called before the wait() in one thread? It's happening with me.

A client requests a value from a target and waits on a result variable RV. In case the target is the client itself, I update RV with the correct result and call notify() on RV in another thread.

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

The problem is that before the requester has completed all the "networking" (sendReqest in the above example) with itself, the result is updated in the result variable. When the requester thread now calls wait(), the program doesn't continue, since notify has already been called.

How can we prevent it?

like image 372
sgarg Avatar asked May 01 '12 08:05

sgarg


3 Answers

You check some flag before waiting (in a loop), see the tutorial: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

like image 89
Walter Laan Avatar answered Sep 29 '22 06:09

Walter Laan


Nothing stops you calling notify on an object that's not being waited by another thread.

It sounds like what you want is a wait only if some condition holds. For example:

synchronized (results) {
    while (!results.hasResults()) {
        // no results yet; wait for them
        try {
            results.wait();
        } catch (InterruptedException ie) { /* ignore */ }
    }
}
like image 28
Joni Avatar answered Sep 29 '22 07:09

Joni


I'd strongly recommend not re-inventing the wheel.

Java's Future interface is designed for results that may only arrive later, and the FutureTask class implements this interface.

Have the first thread obtain access to the Future and get the second thread to run the FutureTask, and all of this stuff gets handled for you. You also get timeout support for free.

like image 20
Bill Michell Avatar answered Sep 29 '22 08:09

Bill Michell