An interesting thing just occurred to me when trying to have a simple demo using wait()
with synchronized
, the following demo is giving me unexpected outputs.
public class WaitZero {
private static AtomicInteger num = new AtomicInteger(0);
private static boolean consumed = false;
public static void main(String... args) throws Exception {
ThreadPoolExecutor threadPoolExecutor = getMyCachedThreadPool();
for (int i = 0; i < 5; i++) {
threadPoolExecutor.submit(WaitZero::send);
threadPoolExecutor.submit(WaitZero::receive);
}
threadPoolExecutor.shutdown();
threadPoolExecutor.awaitTermination(60, TimeUnit.SECONDS);
}
private static synchronized void send() {
try {
while (!isConsumed()) {
num.wait();
}
} catch (InterruptedException ignored) {
ignored.printStackTrace();
}
num.incrementAndGet();
System.out.println(Thread.currentThread().getName() + " number updated: " + num);
setConsumed(false);
num.notifyAll();
}
private static synchronized void receive() {
try {
while (isConsumed()) {
num.wait();
}
} catch (InterruptedException ignored) {
ignored.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " number received: " + num);
setConsumed(true);
num.notifyAll(); // ToDo: when to use notify?
// ToDo: what is monitor?
}
private static boolean isConsumed() {
return consumed;
}
private static void setConsumed(boolean consumed) {
WaitZero.consumed = consumed;
}
}
It's output is not stable but one of the typicals can be
shared-pool-0 number received: 0
shared-pool-1 number updated: 1
shared-pool-0 number received: 1
shared-pool-1 number updated: 2
shared-pool-1 number received: 2
shared-pool-2 number updated: 3
While what I was expecting is
shared-pool-1 number received: 0
shared-pool-0 number updated: 1
shared-pool-3 number received: 1
shared-pool-2 number updated: 2
shared-pool-1 number received: 2
shared-pool-0 number updated: 3
shared-pool-2 number received: 3
shared-pool-3 number updated: 4
shared-pool-5 number received: 4
shared-pool-4 number updated: 5
The correct result is retrieved when I use WaitZero.class
instead of num
on wait()/notifyAll()
.
I've read around and it seems it's always the case that three of them have to be used on the same object to ensure correctness.
My Guess: if not all of them on the same object, there is a special case between the notifyAll()
and the synchronised lock. But what is it?
Any help will be appreciated ;)