3

I have a waiting thread:

synchronized(sharedCounter) {
  while(sharedCounter > 0) {
    sharedCounter.wait(60000); //wait at most 1 minute
    /*if it wakens from the end of the timeout, it should break the loop
      or it could potentially restart the timeout*/
  }
}

And a thread that can notify:

synchronized (sharedCounter) {
  if(sharedCounter == 0) 
    sharedCounter.notify(); 
}

How can I distinguish a notify from a timeout?

I could do something like this:

synchronized(sharedCounter) {
  while(sharedCounter > 0) {
    sharedCounter.wait(60000); 
    if(sharedCounter == -1) { //if it was a notify()
      //I could save the fact that it was a notify() here
      break;
    }
    //Otherwirse, assume it was a timeout, save the fact and break
    break;
  }
}

synchronized (sharedCounter) {
   if(sharedCounter == 0) {
     sharedCounter = -1; //to signal that it comes from a notify()
     sharedCounter.notify(); 
   }
}

The problem is, that a spurious wake up would spoil my design.

How would you handle this problem?

Kami
  • 1,079
  • 2
  • 13
  • 28
  • 2
    What is `sharedCounter`? – hagrawal7777 Jun 21 '15 at 15:09
  • 1
    Adding to hagrawal's comment, I am very concerned about you use of `sharedCounter`. I don't think it's an integer, otherwise you wouldn't be able to synchronize on it. So I assume it's an `Integer`. But it seems dangerous to synchronize on a variable that you are constantly reassigning. – sstan Jun 21 '15 at 15:33
  • You should never assume anything about why `wait()` returned: It should be able to _find out_ why. The wait/notify mechanism is a low-level primitive that is meant to be used in a very specific way to implement higher-level synchronization objects: http://stackoverflow.com/questions/26590542/java-lang-illegalmonitorstateexception-object-not-locked-by-thread-before-wait/26593239#26593239 – Solomon Slow Jun 21 '15 at 17:53

3 Answers3

9

Use a more sophisticated concurrency primitive, a Condition. Acquire one from a Lock with Lock#newCondition(). You then have access to a Condition#await(long, TimeUnit) method which returns a boolean with a value of

false if the waiting time detectably elapsed before return from the method, else true

For example,

ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// ... (share the object across threads)
if (condition.await(10, TimeUnit.SECONDS)) {
    // signaled (equivalent of notify)
} else {
    // time elapsed
}
// ... (in other thread)
condition.signal();

Spurious wakeups, unless otherwise specified in the Condition implementation documentation, are handled internally. You don't have to worry about them.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 1
    Obviously, before calling condition.await(...), I should acquire the lock? – Kami Jun 21 '15 at 16:49
  • 1
    @kami Yes. And `await` releases the corresponding `Lock` until it returns. – Sotirios Delimanolis Jun 21 '15 at 16:50
  • Thanks, it was perfect. Just a question, I am in a scenario where multiple signals could occur. Are they simply ignored (after receiving the firtst one)? – Kami Jun 21 '15 at 17:03
  • 1
    @Kami An `await`-ing `Condition` will consider a single `signal`. Any other `signal` calls will go to other `await`-ing threads or ignored if there are no other threads waiting on the `Condition`. – Sotirios Delimanolis Jun 21 '15 at 17:11
  • The documentation recommends "programmers always assume that [spurious wakeups] can occur". Are you suggesting that doesn't apply to a timed wait? – shmosel May 15 '18 at 04:10
1

There is no way. You will have to add logic to your multithreaded application yourself to distinguish between these cases.

Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
  • A spurious wake up would mess up with the timeout. If it has waited for 30 seconds, I would have no way to reset the wait to only 30 seconds instead of 60 seconds. – Kami Jun 21 '15 at 15:06
  • Actually I found this answer for the timeout: http://stackoverflow.com/questions/8178399/java-how-to-distinguish-between-spurious-wakeup-and-timeout-in-wait It suggests to keep track of the time. – Kami Jun 21 '15 at 15:08
  • @Kami: that would be a terrible solution, since there is no way to tell whether you were notified "just in time" or wether the timeout has passed. – Marcus Müller Jun 21 '15 at 15:10
  • Yes, but I was thinking to combine it with some 'hidden message' like the -1 above. It stil feels like it is not the most clean solution, but it should work. – Kami Jun 21 '15 at 15:14
0

This is a false problem. If, for example, wait returned by timeout, but immediately after that sharedCounter was set to -1 - do you still want to react to timeout, or to -1?

Alexei Kaigorodov
  • 13,189
  • 1
  • 21
  • 38