In this blog I will introduce the thread wait/notify method. Contents include:
wait()
,notify()
,notifyAll()
and other methodswait()
andnotify()
wait(long timeout)
andnotify()
wait()
andnotifyAll()
- Why
notify()
,wait()
and other functions are defined inObject
instead ofThread
wait(), notify(), notifyAll() and other methods
Object.java
defines interfaces such as wait()
, notify()
and notifyAll()
. The role of wait()
is to put the current thread into a wait state. At the same time, wait()
will let the current thread release the lock it holds. The role of notify()
and notifyAll()
is to wake up the waiting thread on the current object; notify()
will wake up a single thread, and notifyAll()
will wake up all threads.
The detailed information about the wait/notify API in the Object
class is as follows:
- notify (): wakes up a single thread waiting on this object monitor.
- notifyAll(): wake up all threads waiting on this object monitor.
- wait(): puts the current thread in the
blocked state (wait)
, until other threads call this object’snotify()
method ornotifyAll()
method”, the current thread is woken up and enter therunnable
state. - wait(long timeout): put the current thread in the
blocked state (wait)
, until other threads call this object’snotify()
method ornotifyAll()
method, or exceed the specified amount of time, the current thread is woken up and enter therunnable
state. - wait(long timeout, int nanos): put the current thread in the
blocked state (wait)
, until other threads call thenotify()
method ornotifyAll()
method of this object, or some other thread interrupts the current thread, or a certain amount of time has been exceeded, the current thread is woken up and enter therunnable
state.
wait() and notify() example
1 | public class WaitAndNotify { |
Results:
1 | main start t1 |
The following figure illustrates the flow of “main thread” and “thread t1”.
- Note that “thread t1” stands for
Thread t1
started inWaitAndNotify
. And “lock” stands for synchronization lock of t1. Main thread
creates a newthread t1
throughnew ThreadA ("t1")
. Then acquire synchronization lock of t1 throughsynchronized(t1)
. Then callt1.start()
to startthread t1
.- The
main thread
executest1.wait()
to release the t1 object’s lock and enters theblocked state (wait)
. Wait for the thread on thet1
object to wake it up vianotify()
ornotifyAll()
. - After
thread t1
runs, it acquire lock of current object throughsynchronized(this)
. Then callnotify()
to wake up “waiting thread on current object”, that is, wake upmain thread
. - After
thread t1
is finished, release lock of current object. Immediately after that, themain thread
acquires the t1 object’s lock and continues running.
For the code above, t1.wait()
should let thread t1
wait; but why did it let main thread
wait?
Let’s look at the comments of wait()
in JDK:
Causes the current thread to wait until it is awakened, typically by being notified or interrupted.
Note: In the comments, wait()
is to let the current thread wait, and the current thread refers to the thread running on the CPU!
This means that although t1.wait()
is the wait()
method called through thread t1
, the place where t1.wait()
is called is in main thread
. The main thread
must be the current thread, which is in running state to execute t1.wait()
. Therefore, the current thread at this time is the main thread
! Therefore, t1.wait()
makes the main thread
wait, not thread t1
!
wait(long timeout) and notify()
wait(long timeout)
will make the current thread in the blocked state (wait)
, until other threads call this object’s notify()
method or notifyAll()
method, or exceed the specified amount of time, the current thread is woken up and enter runnable state
.
1 | public class WaitTimeout { |
Results:
1 | main start t1 |
The following figure illustrates the flow of “main thread” and “thread t1”.
- The
main thread
executest1.start()
to startthread t1
. - The
main thread
executest1.wait(3000)
. At this time, themain thread
enters theblocked state (wait)
. Need the thread used for t1 object lock to wake it up throughnotify()
ornotifyAll()
or after a timeout of 3000ms, themain thread
enters therunnable state
before it can run. - After
thread t1
runs, it enters an endless loop and runs continuously. - After a timeout of 3000ms, the
main thread
will enter therunnable state
, and then enter therunning state
.
wait() and notifyAll()
1 | public class NotifyAll { |
Results:
1 | t1 wait |
main thread
created and startedt1
,t2
andt3
.- The
main thread
sleeps for 3 seconds throughsleep(3000)
. In the process ofmain thread
sleeping, we assume that the three threadst1
,t2
andt3
are all running. Taket1
as an example, when it is running, it will executeobj.wait()
to wait for other threads to wake it up vianotify()
ornofityAll()
. The same reason,t2
andt3
will also wait for other threads to wake them up vianofity()
ornofityAll()
. - After the
main thread
sleeps for 3 seconds, it continue runs and executeobj.notifyAll()
to wake up the waiting thread onobj
, that is, wake up the three threadst1
,t2
andt3
. Immediately after thesynchronized(obj)
of themain thread
is finished, themain thread
releases theobj
lock. In this way,t1
,t2
andt3
can acquire theobj
lock and continue to run!
Why notify(), wait() and other functions are defined in Object instead of Thread
The wait()
, notify()
and other functions in Object
, like synchronized
, will operate on “object synchronization lock”.
wait()
will make the current thread wait, because the thread enters the blocked state (wait)
, so the thread should release the synchronization lock it holds, otherwise other threads cannot obtain the synchronization lock and cannot run!
OK, after the thread calls wait()
, it releases the synchronous lock it holds. According to previous introduction, we know that the waiting thread can be woken up by notify()
or notifyAll()
. Now, think about a question: on what basis does notify()
wake up the waiting thread? In other words, what is the relationship between wait()
and notify()
? The answer is: according to object synchronization lock.
The thread responsible for awakening the waiting thread (we call it “awakening thread”), it is only acquiring the object synchronization lock (the synchronization lock here must be the same as the synchronization lock of the waiting thread), and calling notify()
or notifyAll()
method, the waiting thread can be woken up. Although, the waiting thread is awakened, it cannot be executed immediately because the awakening thread also holds the object synchronization lock. You must wait for the awakening thread to release the object synchronization lock before the waiting thread can acquire the object synchronization lock and continue to run.
In short, notify()
, wait()
depends on object synchronization lock, and object synchronization lock is held by an object, and each object has only one lock! This is why notify()
, wait()
and other functions are defined in the Object
class, not the Thread
class.