3

In the book I'm reading it says:

This technique is needed due to a race condition that would otherwise exist between setting and sending the notification and testing and getting the notification. If the wait() and notify() mechanism were not invoked while holding the synchronization lock, there would be no way to guarantee that the notification would be received.

Don't understand what this exactly means, why can the race condition happen?

EDIT: Hmmmm, I see now that this is possibly a duplicate question of Why must wait() always be in synchronized block , but it seams that the answers focus on making the condition check and going to wait synchronized.

Counterexample from shrini1000:

I can still do something like:
while(!condition) { synchronized(this) { wait(); } }
which means there's still a race between checking the condition and waiting even if wait() is correctly called in a synchronized block. So is there any other reason behind this restriction, perhaps due to the way it's implemented in Java?

5
  • I don't think the answer is there, cause of the counterexample in my question. Commented Dec 14, 2013 at 22:47
  • There is no counterexample here. Your wait() call is in a synchronized block. Commented Dec 14, 2013 at 22:53
  • 1
    The underlying reason is the way the memory model works - you can have a look at: docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.2 for a detailed explanation of how wait sets work. Commented Dec 14, 2013 at 23:09
  • Haven't exactly found there what I was looking for, but for link +1 Commented Dec 14, 2013 at 23:21
  • The fact that something can be misused is hardly a counterexample. Commented Dec 15, 2013 at 10:56

2 Answers 2

3

It must be all about the technique author must have presented before the article you have copied in question. I am not sure which book you are reading but I will try to answer this question.

I read a similar book "Thinking in Java" that talked about the same race condition. It suggests that this can be prevented using wait and notify so that the code doesn't miss the notify signal.

When two threads are coordinated using notify( )/wait( ) or notifyAll( )/wait( ), it’s possible to miss a signal. Suppose T1 is a thread that notifies T2, and that the two threads are implemented using the following (flawed) approach:

T1:

synchronized(sharedMonitor) {
    <setup condition for T2>
    sharedMonitor.notify();
}

T2:

while(someCondition) {
    // Assume that T2 evaluates someCondition and finds 
    // it true, now when program goes to next line thread
    // scheduler switches to T1 and executes notify again
    // after when control comes to T2 it blindly executes
    // wait(), but it has already missed notify so it will
    // always be waiting.

    .... some code ....

    synchronized(sharedMonitor) {
        sharedMonitor.wait();
    }
}

The (setup condition for T2) is an action to prevent T2 from calling wait( ), if it hasn’t already.

The solution is to prevent the race condition over the someCondition variable. Here is the correct approach for T2:

synchronized(sharedMonitor) {
    while(someCondition) {
        sharedMonitor.wait();
    }
}

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, after reading a while I think that the author of the book meant about this case. It's "Java threads, 3rd ed." O'Reilly, I don't recommend.
Hope I have answered your question. Well you can go through thinking in java ( just read concurrency chapter enough for threading ) and for more details jcip is best.
Yes you did, I think you answered what the author intended, but this is not exactly my question. My question is not important anyway. About jcip I have that and I'll read it after reading the current book. I'll give you vote up, but not the mark, cause of this;)
0

The fact that something can be misused is hardly a counterexample.

Java only enforces that wait() and notify() are part of a synchronized block (since that's the only way they are supposed to be used), but it's up to you to define the block boundaries.

As a counter-counterexample, think about the finally block. Java only enforces that it comes after a try block, but you're the only one who should know what's supposed to go into that try block; you could even leave it empty (which would then miss the very point of finally).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.