views:

1258

answers:

7

Someone at work just asked for the reasoning behind having to wrap a wait inside a synchronized.

Honestly I can't see the reasoning. I understand what the javadocs say--that the thread needs to be the owner of the object's monitor, but why? What problems does it prevent? (And if it's actually necessary, why can't the wait method get the monitor itself?)

I'm looking for a fairly in-depth why or maybe a reference to an article. I couldn't find one in a quick google.

Oh, also, how does thread.sleep compare?

edit: Great set of answers--I really wish I could select more than one because they all helped me understand what was going on.

+1  A: 

If the object does not own the object monitor when it calls Object.wait(), it will not be able to access the object to setup a notify listener until the the monitor is released. Instead, it will be treated as a thread attempting to access a method on a synchronized object.

Or to put it another way, there is no difference between:

public void doStuffOnThisObject()

and the following method:

public void wait()

Both methods will be blocked until the object monitor is released. This is a feature in Java to prevent the state of an object from being updated by more than one thread. It simply has unintended consequences on the wait() method.

Presumably, the wait() method is not synchronized because that could create situations where the Thread has multiple locks on the object. (See Java Language Specifications/Locking for more info on this.) Multiple locks are a problem because the wait() method will only undo one lock. If the method were synchronized, it would guarantee that only the method's lock would be undone while still leaving a potential outer lock undone. This would create a deadlock condition in the code.

To answer your question on Thread.sleep(), Thread.sleep() does not guarantee that whatever condition you are waiting on has been met. Using Object.wait() and Object.notify() allows a programmer to manually implement blocking. The threads will unblock once a notify is sent that a condition has been met. e.g. A read from disk has finished and data can be processed by the thread. Thread.sleep() would require the programmer to poll if the condition has been met, then fall back to sleep if it has not.

64BitBob
I understand synchronized. The question was, why does object.wait() need to own the monitor, or why can't the acquisition of that monitor be encapsulated inside the object.wait() method (or is that what Thread.sleep() does?
Bill K
Sorry, I misunderstood. Answer has been updated. Does that answer your question better?
64BitBob
Yes, that makes a good deal of sense, although the open question is still "why can't the wait method just be synchronized itself?"
Bill K
I'd vote this one up if I hadn't down-voted it back before your edits... Unfortunately, it seems old down-votes can't be undone :-(
Bill Michell
I was downvoted to -2. So your +1 is probably working. You could have still selected it as the winning answer, but I see you were more impressed with Robin's. Not to worry, though. It was my fault for initially misunderstanding the question. Thanks for your concern! :-)
64BitBob
+3  A: 

It needs to own the monitor, since the purpose of the wait() is to release the monitor and let other threads obtain the monitor to do processing of their own. The purpose of these methods (wait/notify) is to coordinate access to synchronized code blocks between two threads that require each other to perform some functionality. It is not simply a matter of making sure access to a data structure is threadsafe, but to coordinate events between multiple threads.

A classic example would be a producer/consumer case where one thread pushes data to a queue, and another thread consumes the data. The consuming thread would always require the monitor to access the queue, but would release the monitor once the queue is empty. The producer thread would then only get access to write to the thread when the consumer is no longer processing. It would notify the consumer thread once it has pushed more data into the queue, so it can regain the monitor and access the queue again.

Robin
Good point, but what about the case where you simply want to wait on some notification from another thread, not release a monitor so another thread can have it. Would you say "Thread.sleep" is more appropriate for this usage?
Bill K
In that case, you should probably create another monitor to synchronize between those two threads.
Mr Fooz
If there is no sharing of data structures required, but you simply are waiting for an event to occur, then a sleep may suffice, but the event thread would have to do an interrupt to wake up the sleeping thread (unless timed). Which means it would need access to the thread object.
Robin
In that case you're better off using a Semaphore or a Latch, which one kicks off and the is blocking on await(). There's no direct interaction between then threads, and you can provide semantics around the notification.
Spencer K
+5  A: 

Wait gives up the monitor, so you must have it to give it up. Notify must have the monitor as well.

The main reason why you want to do this is to ensure that you have the monitor when you come back from wait() -- typically, you are using the wait/notify protocol to protect some shared resource and you want it to be safe to touch it when wait returns. The same with notify -- usually you are changing something and then calling notify() -- you want to have the monitor, make changes, and call notify().

If you made a function like this:

public void synchWait() {
   syncronized { wait(); }
}

You would not have the monitor when wait returned -- you could get it, but you might not get it next.

Lou Franco
+1  A: 

Here's my understanding on why the restriction is actually a requirement. I'm basing this on a C++ monitor implementation I made a while back by combining a mutex and a condition variable.

In a *mutex+condition_variable=monitor* system, the wait call sets the condition variable into a wait state and releases the mutex. The condition variable is shared state, so it needs to be locked to avoid race conditions between threads that want to wait and threads that want to notify. Instead of introducing yet another mutex to lock its state, the existing mutex is used. In Java, the mutex is correctly locked when the about-to-wait thread owns the monitor.

Mr Fooz
+6  A: 

Lots of good answers here already. But just want to mention here that the other MUST DO when using wait() is to do it in a loop dependent on the condition you are waiting for in case you are seeing spurious wakeups, which in my experience do happen.

To wait for some other thread to change a condition to true and notify:

synchronized(o) {
  while(! checkCondition()) {
    o.wait();
  }
}

Of course, these days, I'd recommend just using the new Condition object as it is clearer and has more features (like allowing multiple conditions per lock, being able to check wait queue length, more flexible schedule/interrupt, etc).

 Lock lock = new ReentrantLock();
 Condition condition = lock.newCondition();
 lock.lock();
 try {
   while (! checkCondition()) {
     condition.await();
   }
 } finally {
   lock.unlock();
 }

}

Alex Miller
+1  A: 

Mostly wait is done if there is a condition say a queue is empty.

If(queue is empty)
     queue.wait();

Let us assume the queue is empty. In case if the current thread pre-empts after checking the queue, then if another thread adds few elements to queue, the current thread will not know and will go for wait state. Thats wrong. So we should have something like

Synchornized(queue)
{
   if(queue is empty)
          queue.wait();
}

Now let us consider what if they made wait itself as synchronized. As already mentioned in one of the comments, it releases only one lock. That means if wait() was synchronized in the above code only one lock would have been released. Implies that current thread will go for wait with the lock for the queue.

A: 

i cannot explain thread monitors (because i dont know) and i definitely cant wait to see the right answer!

(i wanna comment but i cant dont know why)

brr