In the below example, as the main-thread is not getting notified from the child thread, it should wait forever. But the main-thread is getting executed and the output of the below example is:
c
l
total: 19900
Why is the main-thread getting executed?
public class ThreadX extends Thread {
static int total = 0;
public void run() {
synchronized (this) {
for (int i = 0; i < 200; i++) {
total = total + i;
}
System.out.println("c");
}
}
public static void main(String[] args) throws InterruptedException {
ThreadX t = new ThreadX();
t.start();
synchronized (t) {
t.wait();
System.out.println("l");
}
System.out.println("total: " + total);
}
}
So, when wait() method is called by a thread, then it gives up the lock on that resource and goes to sleep until some other thread enters the same monitor and invokes the notify() or notifyAll() method. Calling notify() wakes only one thread and calling notifyAll() wakes up all the threads on the same object.
In other words, if the notify() method is called when no other thread is waiting, notify() simply returns and the notification is lost. A thread that later executes the wait() method has to wait for another notification to occur.
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.
The wait() method causes the current thread to wait until another thread invokes the notify() or notifyAll() methods for that object. The notify() method wakes up a single thread that is waiting on that object's monitor. The notifyAll() method wakes up all threads that are waiting on that object's monitor.
Check out Thread#join(long)
:
[...] As a thread terminates the
this.notifyAll
method is invoked. [...]
Notice that Thread#join()
calls that function with 0
, which means forever.
[...] A timeout of 0 means to wait forever.
So in your case here t
just calls notifyAll
when it terminates, which notifies the main-thread that is waiting on t
.
This unintuitive behaviour is the reason why they write the following in the documentation:
It is recommended that applications not use
wait
,notify
, ornotifyAll
onThread
instances.
Check out Object#wait
(or JLS (17.2.1. Wait)):
A thread can wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied.
So threads in Java can wake up at any time. A spurious wakeup is not very likely but it can happen.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With