thread - wait method in java




Can anyone explain thread monitors and wait? (4)

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.


A related thread. There is a comment on the accepted answer which suggests a Semaphore or a Latch. Not the same semantics as the above implementation, but handy.


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.


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.


Python “Event” equivalent in Java?

The Object.wait() Object.notify()/Object.notifyAll().

Or Condition.await() and Condition.signal()/Condition.signalAll() for Java 5+.

Edit: Because the python specification is similar how we usually wait a Java implementation would look like this:

class Event {
    Lock lock = new ReentrantLock();
    Condition cond = lock.newCondition();
    boolean flag;
    public void doWait() throws InterruptedException {
        lock.lock();
        try {
            while (!flag) {
                cond.await();
            }
        } finally {
            lock.unlock();
        }
    }
    public void doWait(float seconds) throws InterruptedException {
        lock.lock();
        try {
            while (!flag) {
                cond.await((int)(seconds * 1000), TimeUnit.MILLISECONDS);
            }
        } finally {
            lock.unlock();
        }
    }
    public boolean isSet() {
        lock.lock();
        try {
            return flag;
        } finally {
            lock.unlock();
        }
    }
    public void set() {
        lock.lock();
        try {
            flag = true;
            cond.signalAll();
        } finally {
            lock.unlock();
        }
    }
    public void clear() {
        lock.lock();
        try {
            flag = false;
            cond.signalAll();
        } finally {
            lock.unlock();
        }
    }
}




monitor