Producer - Consumer Threads why use "while" loop instead of "if"?

U

Usenet Poster!!!

I've been going over some code with a colleague on thread
synchronization
and he used an 'if' instead of a 'while' loop to wait().

public synchronized Object pop() {
if (isEmpty()) {
try {
wait();
} catch (InterruptedException e) {
}
}
 
A

andreas

Usenet Poster!!! said:
I've been going over some code with a colleague on thread
synchronization
and he used an 'if' instead of a 'while' loop to wait().

public synchronized Object pop() {
if (isEmpty()) {
try {
wait();
} catch (InterruptedException e) {
}
}
.
.
.
notify();
return obj;
}

likewise there is a synchronized method to push(). (For full example
check out any standard Java book that teaches threads).

I corrected it by changing the if() statement to a while().

However, I couldn't explain satisfactorily *why* it must be a loop
instead of an if. It's just always written in the books that that is
the way.

The notify() statement will only notify 1 thread, so how could another
thread consume (pop) if i was the only thread notified and woken up
(since the rest are still waiting)?

And shouldn't a return from wait() mean that you have reacquired the
lock? So how could other threads return from wait() when my woken
thread has the lock?

Please reply to group as the email I'm using is invalid.

Regards,

Nico.

your code looks like a stack implementation. you don't want to pop an
element
if there is none, so you wait until the stack is not empty anymore.

wait() puts a thread to sleep until some trigger occurs. this trigger does
not necessarily
mean that an object was pushed. it could happen, that the thread awakens due
to some
other trigger. in this case, the IF solution would just continue (wrongly)
while the WHILE
solution checks again, if it really isn't empty. if it still is, the thread
goes back to sleep.

if i remember correctly, in unix the action of putting a thread to sleep is
removing it from
the "active"-queue and adding it to the "asleep"-queue.
i assume java handles this in a similar manner.

HTH and makes more or less sense...

andreas
 
C

Chris Uppal

Usenet said:
However, I couldn't explain satisfactorily *why* it must be a loop
instead of an if. It's just always written in the books that that is
the way.

There are two problems.

One is that you don't know for sure /why/ your wait has been interrupted, so
you should retest the condition. It may turn out not to be true (if you have
been interrupted for some other reason), in which case you need to go back to
sleep. It may be that in some specific application you could prove to your own
satisfaction that there was /no possible/ way that a thread could be woken up
without the condition it was waiting on being true, but why go to that effort
(and why put everyone who subsequently reads the code to the same effort) ?
Even if you do consider everything in your proof (and get it right) you have
created a fragile system that can easily be broken by subsequent maintenance.
Much better just to stick with the standard idiom which is familiar to most
programmers, and which is known to work.

The other reason is that using notify() rather than notifyAll() is fragile.
You have to be /absolutely sure/ that the thread you are notify()-ing is
actually waiting on the object in question. That can be very difficult,
especially since you can easily get race conditions where the notify() happens
before the point where the other thread enters its wait(). If, as is likely,
you cannot be sure that 1 /specific/ thread is waiting, then you have to use
notifyAll(), and since all the threads that are waiting will wake up, you have
to ensure that all but one of them will go back to sleep again.

Incidentally, you wrote
(For full example
check out any standard Java book that teaches threads).

/THE/ book on Java threads is Doug Lea's "Concurrent Programming in Java" which
includes a full discussion of this point. If you don't have it already then I
advise buying it today[*]. It's invaluable.

([*] and it you do have it already, then I advise reading it today ;-)

-- chris
 
U

Usenet Poster!!!

thanks to everyone who replied...

Chris Uppal said:
Usenet said:
However, I couldn't explain satisfactorily *why* it must be a loop
instead of an if. It's just always written in the books that that is
the way.

There are two problems.

One is that you don't know for sure /why/ your wait has been interrupted, so
you should retest the condition. It may turn out not to be true (if you have
been interrupted for some other reason), in which case you need to go back to
sleep. It may be that in some specific application you could prove to your own
satisfaction that there was /no possible/ way that a thread could be woken up
without the condition it was waiting on being true, but why go to that effort
(and why put everyone who subsequently reads the code to the same effort) ?
Even if you do consider everything in your proof (and get it right) you have
created a fragile system that can easily be broken by subsequent maintenance.
Much better just to stick with the standard idiom which is familiar to most
programmers, and which is known to work.

The other reason is that using notify() rather than notifyAll() is fragile.
You have to be /absolutely sure/ that the thread you are notify()-ing is
actually waiting on the object in question. That can be very difficult,
especially since you can easily get race conditions where the notify() happens
before the point where the other thread enters its wait(). If, as is likely,
you cannot be sure that 1 /specific/ thread is waiting, then you have to use
notifyAll(), and since all the threads that are waiting will wake up, you have
to ensure that all but one of them will go back to sleep again.

Incidentally, you wrote
(For full example
check out any standard Java book that teaches threads).

/THE/ book on Java threads is Doug Lea's "Concurrent Programming in Java" which
includes a full discussion of this point. If you don't have it already then I
advise buying it today[*]. It's invaluable.

([*] and it you do have it already, then I advise reading it today ;-)

-- chris
 
E

Eric Sosman

Usenet said:
I've been going over some code with a colleague on thread
synchronization
and he used an 'if' instead of a 'while' loop to wait().
[... stack-pop implementation snipped ...]
The notify() statement will only notify 1 thread, so how could another
thread consume (pop) if i was the only thread notified and woken up
(since the rest are still waiting)?

Others have mentioned that wait() might awaken for
unanticipated reasons, and have talked about notify()
vs. notifyAll(). Here's another scenario:

Thread A finds the stack empty and puts itself
to sleep with wait().

Thread B pushes something on the stack and
calls notify() to awaken A.

"Awakening" is not instantaneous. Not only
that, but A needs to re-aquire the lock. And
while all this is going on ...

... Thread C, which has been happily running
all this time, chooses this moment to pop the
stack. It finds the stack non-empty, removes
the object B put there, and goes about its
business without ever wait()ing at all.

Finally, Thread A finishes rubbing the sleepy
sand from its eyes and finds itself awake and
running, just after the wait().

Now: Is it safe for A to pop an object off the top of
the stack? No -- the stack is empty because C has already
popped it. Thread A must re-test the "stack empty"
condition and go back to sleep again.

Another way to look at the situation is to realize
that the state of a shared object can change at any time
while you're not holding its lock. Some period of time
elapses between the notify() or notifyAll() and the moment
when the awakened thread re-acquires the lock, and the
state of the object can change during that time.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top