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.