Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait() and Notify() concepts - Java Multithreading

class Q {
  volatile boolean valueSet = false;
  volatile int n;

  synchronized int get () {
    if ( !valueSet ) {
      try {
        wait();
      } catch ( InterruptedException e ) {
        System.out.println( "InterruptedException caught" );
      }
    }

    System.out.println( "Got: " + n );
    valueSet = false;
    notify();
    return n;
  }

  synchronized void put ( int n ) {
    if ( valueSet ) {
      try {
        wait();
      } catch ( InterruptedException e ) {
        System.out.println( "InterruptedException caught" );
      }
    }

    this.n = n;
    valueSet = true;
    System.out.println( "Put: " + n );
    notify();
  }
}

class Producer
    implements Runnable {
  Q q;
  Producer ( Q q ) {
    this.q = q;
    new Thread( this, "Producer" ).start();
  }

  public void run () {
    int i = 0;
    while ( true ) {
      q.put( i++ );
    }
  }

}

class Consumer
    implements Runnable {
  Q q;
  Consumer ( Q q ) {
    this.q = q;
    new Thread( this, "Consumer" ).start();
  }

  public void run () {
    while ( true ) {
      q.get();
    }
  }

}

class PCFixed {
  public static void main ( String args[] ) {
    Q q = new Q();
    new Producer( q );
    new Consumer( q );
    System.out.println( "Press Control-C to stop." );
  }
}

I'm unable to understand how this works. Take this flow for instance. Producer enters put method and calls notify(). What if wait() has not been called by the consumer yet? Also, once the producer calls notify(), how can the consumer enter the method get() when the producer has not let go of the monitor yet? Please help me out here.

like image 649
Cafecorridor Avatar asked Nov 30 '25 17:11

Cafecorridor


2 Answers

I'm assuming that the class at the top is Q, it's missing some code. Anyway, the general idea is that the boolean valueSet and the wait()/notify() calls work in tandem.

If the consumer has already begun to wait, he has acquired the lock to the Q instance through the synchronized get() method and then releases it while he waits.

If the consumer has not begun to wait yet, the producer may have the lock to the Q instance because the put() method is synchronized on that same lock. Once the producer exits the lock, he will have called notify() as well as set the valueSet boolean to true.

The consumer's next call to get() will read the boolean value before attempting to wait, notice that something's there, take the contents of n and do whatever work is needed. If the value had not been set, meaning that nothing had come in in the consumer's absence, he would wait() on the lock for new work and the next notify() will wake him up.

Update

In your scenario in the comments, you're essentially asking about the exact same situation but in reverse. The same logic applies.

The consumer is currently waiting and the producer calls notify(). The producer currently has the lock and will continue to hold the lock for the duration of the method. All notify() does is let one other thread currently waiting on the lock know that, when the lock is released, it can try to take the lock and resume execution. In this case, there is only one other thread, but if there were multiple threads then it would select only one (to wake everyone, notifyAll() should be called).

  1. The producer exits the method, releasing the lock.
  2. The consumer wakes up and takes the lock.

At this point, it's ambiguous as to whether the producer has already come around and is currently waiting on the lock or if it has not entered the method yet. The same tandem of the boolean flag and wait()/notify() applies to this as well.

Before the consumer releases the lock by exiting the method, it will both set the boolean flag to false and call notify().

If the producer is currently already waiting on the lock, calling notify() will let it know that it can wake up and continue when the lock is released.

If the producer is not waiting through a wait() call, it must be outside the method (possibly waiting to enter the method and acquire the lock that way). When the consumer exits the method and releases the lock, the producer acquires it and checks the boolean flag. It's been set to false, therefore the producer does not attempt to call wait() and just drops its value off, sets the boolean flag and calls notify().

like image 160
Chris Hannon Avatar answered Dec 03 '25 08:12

Chris Hannon


  1. What if wait() has not been called by the consumer yet?
    • The message will be lost
  2. Once the producer calls notify(), how can the consumer enter the method get() when the producer has not let go of the monitor yet?
    • It will deadlock - block until it the monitor is realeased.
like image 36
SliverNinja - MSFT Avatar answered Dec 03 '25 09:12

SliverNinja - MSFT



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!