I have one Calculator thread that calculates the sum of number from 1 to 50, and multiple Reader threads that show the result once Calculator thread is ready. I have an option of calling notify() and notifyAll() to signal the Reader threads that the result of calculation is ready to display. At LINE B of Calculator class, if I call the notifyAll() method, the result is printed 4 times as expected. But when I replace LINE B with just notify() still I see the result printed 4 times which does not seem to be correct. It is my understanding that notify() will only wakes up one of the threads that is waiting, not all. Why are all of the threads waking up and printing the result when I call notify?
public class ThreadWaitNotify {
public static void main(String[] args) {
Calculator c = new Calculator();
Reader r = new Reader(c);
Reader r2 = new Reader(c);
Reader r3 = new Reader(c);
Reader r4 = new Reader(c);
r.start();
r2.start();
r3.start();
r4.start();
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.start();
}
}
Reader class:
class Reader extends Thread {
Calculator c;
public Reader(Calculator c) {
this.c = c;
}
@Override
public void run() {
synchronized (c) {
try {
System.out.println(Thread.currentThread().getName() + " Waiting for calculations: ");
c.wait(); // LINE A
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " Total: " + c.getSum());
}
}
}
Calculator class:
class Calculator extends Thread {
private int sum = 0;
@Override
public void run() {
synchronized (this) {
for (int i = 1; i <= 50; i++) {
sum += i;
}
notify(); // LINE B
}
}
public int getSum() {
return sum;
}
}
Output:
Thread-1 Waiting for calculations:
Thread-4 Waiting for calculations:
Thread-3 Waiting for calculations:
Thread-2 Waiting for calculations:
Thread-1 Total: 1275
Thread-2 Total: 1275
Thread-3 Total: 1275
Thread-4 Total: 1275
======================
UPDATE: Using an object as a monitor/lock instead of a Thread instance produces the correct behavior.
Updated ThreadWaitNotify Class:
public class ThreadWaitNotify {
public static void main(String[] args) {
Object monitor = new Object();
Calculator c = new Calculator(monitor);
Reader r = new Reader(c, monitor);
Reader r2 = new Reader(c, monitor);
Reader r3 = new Reader(c, monitor);
Reader r4 = new Reader(c, monitor);
r.start();
r2.start();
r3.start();
r4.start();
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.start();
}
}
Updated Reader Class:
class Reader extends Thread {
Calculator c;
Object monitor;
public Reader(Calculator c, Object monitor) {
this.c = c;
this.monitor = monitor;
}
@Override
public void run() {
synchronized (monitor) {
try {
System.out.println(Thread.currentThread().getName() + " Waiting for calculations: ");
monitor.wait(); // LINE A
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " Total: " + c.getSum());
}
}
}
Updated Calculator Class:
class Calculator extends Thread {
private int sum = 0;
Object monitor;
public Calculator(Object monitor) {
this.monitor = monitor;
}
@Override
public void run() {
synchronized (monitor) {
for (int i = 1; i <= 50; i++) {
sum += i;
}
monitor.notify(); // LINE B
}
}
public int getSum() {
return sum;
}
}