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

Discussion in 'Java' started by Usenet Poster!!!, Sep 29, 2004.

  1. 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) {
    }
    }
    Usenet Poster!!!, Sep 29, 2004
    #1
    1. Advertising

  2. Usenet Poster!!!

    andreas Guest

    "Usenet Poster!!!" <> schrieb im Newsbeitrag
    news:...
    > 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
    andreas, Sep 29, 2004
    #2
    1. Advertising

  3. Usenet Poster!!!

    Chris Uppal Guest

    Usenet Poster!!! wrote:

    > 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
    Chris Uppal, Sep 29, 2004
    #3
  4. thanks to everyone who replied...

    "Chris Uppal" <-THIS.org> wrote in message news:<>...
    > Usenet Poster!!! wrote:
    >
    > > 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
    Usenet Poster!!!, Sep 30, 2004
    #4
  5. Usenet Poster!!!

    Eric Sosman Guest

    Usenet Poster!!! wrote:
    > 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.

    --
    Eric Sosman, Sep 30, 2004
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mark McKay
    Replies:
    0
    Views:
    432
    Mark McKay
    Dec 9, 2003
  2. Buck Turgidson

    Simple Producer/Consumer Thread Question

    Buck Turgidson, Feb 17, 2004, in forum: Java
    Replies:
    5
    Views:
    517
    Tony Dahlman
    Feb 21, 2004
  3. Jeff
    Replies:
    4
    Views:
    657
    xarax
    Oct 22, 2004
  4. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,733
    Smokey Grindel
    Dec 2, 2006
  5. Melzzzzz
    Replies:
    39
    Views:
    1,823
    Melzzzzz
    Jul 29, 2012
Loading...

Share This Page