Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issuing notify on a single thread awakens all waiting threads

Having three threads waiting on a 4th one, and the latter issuing a notify, all of the waiting threads are awakened.

Here is the source code:

class Reader extends Thread {

  Calculator calc;

  public Reader(Calculator calc) {
    this.calc = calc;
  }

  public void run() {
    synchronized(calc) {
      try {
        System.out.println(Thread.currentThread().getName() + " waiting for calc");
        calc.wait();
      } catch (InterruptedException e) { e.printStackTrace(); }
      System.out.println(Thread.currentThread().getName() + " Total is: " + calc.total);
    }   
  }

}

class Calculator extends Thread {

  public int total = 0;

  public void run() {
    synchronized(this) {
      for (int i = 0; i < 50; i++) {
        total += i;
      }
      notify();
      System.out.println("I notified a thread");
    }
  }

}

public class Notify {

  public static void main(String[] args) {
    Calculator calc = new Calculator();
    Reader r1 = new Reader(calc);
    Reader r2 = new Reader(calc);
    Reader r3 = new Reader(calc);
    r1.start();
    r2.start();
    r3.start();
    calc.start();
  }
}

Here is the output I get:

Thread-2 waiting for calc
Thread-4 waiting for calc
Thread-3 waiting for calc
I notified a thread
Thread-2 Total is: 1225
Thread-3 Total is: 1225
Thread-4 Total is: 1225

Shouldn't only one waiting thread be awakened and execute the System.out.println(Thread.currentThread().getName() + " Total is: " + calc.total); instruction ?

like image 602
Jihed Amine Avatar asked Jan 19 '26 02:01

Jihed Amine


1 Answers

You can't use wait/notify this way. You have to use wait to wait for something, something your code can, and must, test. You should only call notify after changing something that another thread is actually waiting for such that its test will tell it to no longer wait for it.

"A thread can also 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."

In other words, your wait logic must look like this:

  1. Can I do something now?
  2. If no, call wait and go to step 1.
  3. Do that thing.

And your notify logic must look like this:

  1. Make it so that another thread can do something.
  2. Call notify.

These functions are not a generic suspend/resume mechanism. They are specifically a way to synchronize on a predicate managed by code protected by the synchronized block. You can build a suspend/resume mechanism out of them if you want by using your own suspect/resume flag or count if you want to.

Update: Måns Rolandi Danielsson figured out what's going on in your specific case. Your threads are waiting for an object that hasn't launched/terminated already. So when it signals itself that it is ready/finished, the other threads see that signal.

like image 116
David Schwartz Avatar answered Jan 21 '26 17:01

David Schwartz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!