Why wait(), notify(), notifyAll() must be called inside a synchronized method/block?

In Java, any object can act as a monitor - that's an entity with a single lock, an entry queue, and a waiting queue. An object's method without qualifed by the keyword synchronized  can be invoked by any number of  threads at any time, the lock is ignored. The synchronized method of an object, one and only one thread, who owns the lock of that object, can be permitted to run that method at any time;i.e. a synchronized method is mutually exclusive . If, at the time of invocation, another thread owns the lock, then the calling thread will be put in the Blocked state and is added to the entry queue.

The wait(), notify(), and notifyAll() methods should be called for an object only when the current thread has already locked the object's lock. This point sometimes goes unnoticed because programmers are used to calling these methods from within synchronized methods or blocks. Otherwise, you will get "java.lang.IllegalMonitorStateException: current thread not owner" at runtime.

When a thread running in a synchronized method of an object is calling the wait() method of the same object, that thread releases the lock of the object and is added to that object's waiting queue. As long as it's there, it sits idle. Note also that wait() forces the thread to release its lock. This means that it must own the lock of an object before calling the wait() method of that (same) object. Hence the thread must be in one of the object's synchronized methods or synchronized block before calling wait().

When a thread invokes an object's notify() or notifyAll() method, one (an arbitrary thread) or all of the threads in its waiting queue are removed from the waiting queue to the entry queue. They then actively contend for the object's lock, and the one that gets the lock goes on to execute. If no threads are waiting in the waiting queue, then notify() and notifyAll() have no effect. Before calling the notify() or notifyAll() method of an object, a thread must own the lock of the object. Hence it must be in one of the object's  synchronized methods or synchronized block.

A thread in the waiting queue of an object can run again only when some other thread calls the notify() (or the notifyAll) method of the same object.

The reason to call wait() is that the thread does not want to execute a block of code until a particular state to be achieved. It wants to wait until a particular state to be achieved. The reason to call notify() or notifyAll() method is that the thread will signal others that "a particular state has been achieved". The state is a communication channel between threads and it must be shared mutable state.

For example, one thread read data from a buffer and one thread write data into buffer. The reading data thread needs to wait until the writing data thread completly write a block data into the buffer. The wirting data thread needs to wait until the reading data thread completly read the data from the buffer. If wait(), notify(), and notifyAll() methods can be called by a ordinary method , the reading thread calls wait() and the thread is being added to waiting queue . At just the same moment, the writing thread calls notify() to signal the condition changes. The reading thread misses the change and waits forever. Hence, they must be called inside a synchronized method or block which is mutually exclusive.


Chapter 20 of Inside the Java Virtual Machine - Thread Synchronization by Bill Venners

Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend

Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |