notfiy() and wait()

R

Richard Wilson

Can anyone shed any light on why the wait() method doesn't recognise
that a notify() has occured before it's called?

I have a simple thread for a message queue running a loop like:

public synchronized void addItem(Object item) {
list.addElement(item);
notify();
}

public synchronized void stop() {
running = false;
notify();
}

public void run() {
while (running) {
synchronized(this) {
if (list.size() != 0) {
copy the items
list.removeAllElements();
}
}
processItems();
synchronized(this) {
wait();
}
}
}

This keeps the synchronization blocks to a minimum, and means
processItems won't block the addItem method for long periods. The
problem is that if the addItem (or stop) method gets called while
the thread is in processItems, then the wait() call doesn't get
notified. I know it's easy enough to work around this using
another if just before the wait, but why on earth was
the wait/notify mechanism designed this way?

Richard
 
H

hiwa

Richard said:
the addItem (or stop) method gets called while
the thread is in processItems, then the wait()
call doesn't get notified.
No wonder. It's simpley a bad design.
By the way, the canonical form of wait() call
should be:
public synchronized void get(){ // acquire lock
// or
// synchronized(...){
while (! available) { //check condition state
try {
wait();
}
catch (Exception e) {
...
}
}
...
}
 
H

hiwa

hiwa said:
Couldn't you dispatch another thread for processItems() task?
Or, simple conditional around a boolean state might be used instead of
wait/notify.
 
E

Eric Sosman

Richard said:
Can anyone shed any light on why the wait() method doesn't recognise
that a notify() has occured before it's called?

Because it's not supposed to.

Here's an analogy -- analogies are imperfect, but can help
someone get to the "Aha!" moment. When you arrive at a busy
intersection you check the traffic signal to decide whether to
proceed or to stop (at least, I hope you do). The crucial datum
is the current state of the intersection: is it currently devoted
to traffic flowing in your direction, or to the crossing traffic?
You query the traffic light to learn the current state, and act
accordingly.

Now, let's do it with notifications. The traffic light goes
away and is replaced by a transmitter that sends a "BEEP" when
the intersection switches to North-South mode and a "BOOP" when it
reverts to East-West traffic. Your car has a radio that picks up
these signals. As you approach the intersection on the N-S road
you ask "Have I heard a BEEP?" Yes, of course you have -- you've
been listening for the last five minutes -- so you drive happily
into the intersection and get obliterated by an E-W cement truck.

What was wrong with your strategy? Simple: The "BEEP" signals
a *change* of state, but does not promise that the new state will
remain unchanged forever, or even until someone becomes interested.
The fact that the intersection has been in the N-S mode is of no
use to you; it may have changed to E-W and back to N-S and back to
E-W again any number of times since that "BEEP" was broadcast. You
need to base your decision on the current state of the intersection,
not on its past history.

Back to Java: When you wait() for something, you are not (or
should not be) waiting for a signal, but waiting for a status. At
some point you acquire the lock on an object, examine its state,
and decide that you can't do anything with it at the moment. So
you call wait() to put yourself to sleep until such time as some
other thread changes the object's state. When that other thread
makes the change it calls notify() *not* to tell you that you can
now proceed, but to say "I've changed something that *might* be of
interest; you should wake up and check the state again." After all,
that other thread doesn't really know what you're waiting for: You
might be waiting for an item to be inserted on a formerly empty
queue so you can peel it off, or you might be waiting for somebody
to remove an item from a full queue so you can deposit another. All
the notifying thread says is "Hey, the state of the queue has changed
and you might be interested." (For notifyAll(), change "Hey" to
"Hey, everybody.")

Back to the traffic light again: You're waiting at the red light,
and it turns green. Can you cross the intersection? If you're near
the front of the line you can, but what if you're twenty cars behind
the leader and it's a short-cycle light? You may have to wait through
more than one cycle before you actually get your chance to cross.
Again, the fact that the light turned green while you waited does not
mean that it is still green when you need it to be: You must check
the state of affairs when you actually get to the verge. In Java
terms, when you awaken from a wait() it does not mean the situation
you were waiting for now holds, it just means that you should check
again -- and perhaps sigh, put on the brakes, and wait() through
another light cycle.
 
C

Christopher Benson-Manica

Richard Wilson said:
Can anyone shed any light on why the wait() method doesn't recognise
that a notify() has occured before it's called?

To produce the behavior you want, the implementation would have to
store a flag (or possibly a list) of pending notify() calls so that
ensuing wait() calls could return immediately. Not only would that
introduce a lot of bookkeeping overhead, a programmer who didn't want
this behavior would be out of luck.

Additionally, java.util.concurrent.Semaphore (from 1.5) is at least
one option to get the behavior you want.
 
T

Thomas Hawtin

Richard said:
I have a simple thread for a message queue running a loop like:

You know you could just use a BlockingQueue? There is less need to use
wait and notify/notifyAll these days, and the java.util.concurrent
collections are fast and (highly unusually for multi-threaded code)
appear to be mostly bug-free.

Tom Hawtin
 

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,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top