Questions about timing within synchronized blocks


R

Robert Mark Bram

Hi All!

I have some questions about timing with synchronization.. Which is better:

Object sync;
....
synchronized (sync){
// Do important stuff..
sync.notifyAll();
} // end synchronized

or this:
synchronized (sync){
// Do important stuff..
} // end synchronized
sync.notifyAll();

In the first example, is there any chance that the timing will stuff up and
when blocked threads get notified, Java still thinks control is in the
synchronized section?

If I do something like this:
synchronized (sync){
// Do important stuff..
sync.notifyAll();
// Do more important stuff..
} // end synchronized

Obviously this is deadlock making code.. but what if "Do more important
stuff" was just "i+=1".. could it still work then?

Thanks for any advice!

Rob
:)
 
Ad

Advertisements

C

Carl Howells

Robert said:
Hi All!

I have some questions about timing with synchronization.. Which is better:

Object sync;
...
synchronized (sync){
// Do important stuff..
sync.notifyAll();
} // end synchronized

or this:
synchronized (sync){
// Do important stuff..
} // end synchronized
sync.notifyAll();

The second case will throw an IllegalMonitorStateException. (I think
that's the name of the exception, anyway.) Calls to wait and
notify[all] must be inside blocks synchronized on the object they're
being called on.
In the first example, is there any chance that the timing will stuff up and
when blocked threads get notified, Java still thinks control is in the
synchronized section?

No. But see below. You are *very* confused.
If I do something like this:
synchronized (sync){
// Do important stuff..
sync.notifyAll();
// Do more important stuff..
} // end synchronized

Obviously this is deadlock making code.. but what if "Do more important
stuff" was just "i+=1".. could it still work then?

That code has no more chance of causing a deadlock than if all the
important stuff was before the notifyAll call.

You completely don't understand the semantics of wait and notify.
(notifyAll is just a special case of notify, so I won't bother
mentioning it explicitly further.)

When you call wait on an object, you first must have that object's lock.
(In other words, be in code that has synchronized on that object.)
When wait is called, it does two things (initially). First, it
*releases* the lock on the object it was called on. Second, it puts the
current thread into a non-runnable (system dependent for the details,
but whatever) state, and then execution moves to some other thread.

When you call notify on an object, you first must have that object's
lock. (Same as with wait). When notify is called, it does one thing
directly, which is to put some thread (if any exist anyway) that is
waiting on that object back into the runnable state. But notify doesn't
cause the lock to be released in the current thread, nor does it cause
the waiting thread to gain the lock. (This is the only spot notifyAll
differs from notify, in that notifyAll performs that action for *all*
waiting threads. But the difference is very minor, and typically notify
does what you want anyway.)

Then, the code that called notify continues executing. Any threads that
were waiting attempt to regain the lock on the object they waited on.
The wait() method won't actually return until that lock is re-acquired.
So, the wait() call won't ever return for more than one thread
simultaneously, and it won't ever return until the code that notified it
leaves the synchronized block in which it acquired the lock for that
object. (Or if it was a version of wait that had a timeout, and timed
out, wait won't return until it reacquires the lock on the object, which
may or may not be immediate, depending on whether there is contention
for the lock.)

In summary... Your first and third code samples are indistinguishable
from the standpoint of execution behavior. The second code sample is
just broken, because notify is called at an illegal time.
 
R

Robert Mark Bram

Hi Carl,

Thank you for letting me know that notifyAll() outside a synchronized block
is illegal.

I found the answer I was looking for elsewhere (mental note: google first!):
- an object entering the synchronized code will block (something like an
implicit wait()) if it doesn't own the lock;
- code leaving the synchronized block will wake up one waiting thread, if
any (something like an implicit notifyAll();
- I don't need any notify calls in the synchronized block because Java
implicitly handles this.

Rob
:)
 
Ad

Advertisements

X

xarax

Robert Mark Bram said:
Hi Carl,

Thank you for letting me know that notifyAll() outside a synchronized block
is illegal.


I found the answer I was looking for elsewhere (mental note: google first!):
- an object entering the synchronized code will block (something like an
implicit wait()) if it doesn't own the lock;
- code leaving the synchronized block will wake up one waiting thread, if
any (something like an implicit notifyAll();
- I don't need any notify calls in the synchronized block because Java
implicitly handles this.

You only need the notify[All] calls when other threads
have called wait() on the synchronized object. If you're
intent is to create a critical section of code where only
one thread at a time may "do important stuff" to the object,
then you only need to synchronize on that object.

OTOH, if other threads are waiting for work to do (like
waiting on an event queue for a message object to arrive),
then you need wait() and notify(). A thread that wants to
pull a message from an event queue will wait() on that
queue (when the queue is empty) for another thread to call
notify() after it has placed a new message onto the queue.
 

Top