Reputation: 43
In the following code two consumer threads start and become waiting. The producer thread starts (very likely) after that and calls 'notify'. All threads use the producer as monitor.
Thread producer = new Thread() {
@Override
public void run() {
synchronized (this) {
System.out.printf("notify at %d %n", getId());
notify();
}
}
};
Runnable consumer = () -> {
try {
synchronized (producer) {
long id = Thread.currentThread().getId();
System.out.printf("wait at %d %n", id);
producer.wait();
System.out.printf("awakened: %d %n", id);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Stream.generate( () -> consumer )
.limit(2)
.map(Thread::new)
.forEach(Thread::start);
Thread.sleep(3000); // consumer threads are (likely) waiting
producer.start();
From javadoc for Object.notify:
Wakes up a single thread that is waiting on this object's monitor.
The code produces this (or similar) output:
wait at 13
wait at 14
notify at 12
awakened: 13
awakened: 14
The point is that both consumer threads are awakened, not just one of them. Why?
Compiled and tested with OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.5+10) under Windows 10, 64-bit.
Thanks in advance!
Upvotes: 4
Views: 328
Reputation: 308169
The issue is that instead of an arbitrary Object
you use a Thread
as the monitor.
Thread
uses signals internally as documented in Thread.join
:
As a thread terminates the
this.notifyAll
method is invoked. It is recommended that applications not usewait
,notify
, ornotifyAll
onThread
instances.
The general suggestion is to always use dedicated objects to wait
/notify
on that no other code can get access to to avoid "spurious" notifies or waits like this.
Upvotes: 9