Aquib Javed
Aquib Javed

Reputation: 15

Wait and Notify not behaving as expected , thread is getting hanged

Below is the code sample: Thread is getting hanged after consuming 5 or 6 values I do not know where i am missing anything.And one more doubt that i Had was regarding calling the constructor of the MyIncrementor class. Initially I was trying to call the get and set in Producer and Consumer Class by creating new object of the MyIncrementor class, it was not working too

/**
 * 
 */
package multithreadingDemo;

/**
 * @author Aquib
 *
 */
public class ThreadCommDemo {

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        MyIncrementor mi=new MyIncrementor();
        Producer1 p=new Producer1(mi);
        Consumerrs c=new Consumerrs(mi);
        Thread t1=new Thread(p);
        Thread t2=new Thread(c);
        t1.start();
        t2.start();


    }

}



class MyIncrementor {
    int myCount;
    boolean valueSet;

    /**
     * @return the myCount
     */
    public synchronized int getMyCount() {
        if (!valueSet) {
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("get" + myCount);
        valueSet = true;
        notifyAll();
        return myCount;
    }

    /**
     * @param myCount
     *            the myCount to set
     */
    public synchronized void setMyCount(int myCount) {
        if (valueSet) {
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("Set" + myCount);
        this.myCount = myCount;
        valueSet = false;
        notifyAll();
    }

}

class Producer1 implements Runnable {
    MyIncrementor mi;

    public Producer1(MyIncrementor mi) {
        // TODO Auto-generated constructor stub
        this.mi=mi;
    }

    public void run() {

        for (int i = 1; i < 10; i++) {
            mi.setMyCount(i);
            System.out.println("Produced" + mi.myCount);
             try 
             {
                   Thread.currentThread().sleep((int)(Math.random() * 100));
             } 
             catch (InterruptedException ie) 
             {
                   ie.printStackTrace();
             }
        }
    }
}

class Consumerrs implements Runnable {
    MyIncrementor mi;

    public Consumerrs(MyIncrementor mi) {
        // TODO Auto-generated constructor stub
        this.mi=mi;
    }

    public void run() {

        for (int i = 1; i < 10; i++) {
            int val = mi.getMyCount();
            System.out.println("Consumed" + val);
        }

    }

}

Upvotes: 1

Views: 48

Answers (2)

Sergei Sirik
Sergei Sirik

Reputation: 1289

You just have logical mistakes in your MyIncrementor class, you are setting valueSet incorrectly, so you have to either change your conditions or set the flag vice versa in getMyCount and setMyCount methods.

So, here is the corrected version of MyIncrementor:

class MyIncrementor {
  int myCount;
  boolean valueSet = false; //line changed - just to show that by default it is initialized to false

  /**
   * @return the myCount
   */
  public synchronized int getMyCount() {
    while (!valueSet) { //corrected as advised in comments, see @Tom Hawtin - tackline answer for details
      try {
        wait();
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    System.out.println("get" + myCount);
    valueSet = false; //line changed - after getting the value set flag to false
    notifyAll();
    return myCount;
  }

  /**
   * @param myCount
   *            the myCount to set
   */
  public synchronized void setMyCount(int myCount) {
    while (valueSet) { //corrected as advised in comments, see @Tom Hawtin - tackline answer for details
      try {
        wait();
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    System.out.println("Set" + myCount);
    this.myCount = myCount;
    valueSet = true; //line changed - after setting the value set flag to true
    notifyAll();
  }

}

Upvotes: 1

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147154

The first thing that stands out is the lack of a while.

    if (valueSet) { // <-- if is wrong
        try {
            wait();

wait should be in a while. This ensures that the condition is met, rather than waking up for some other reason or no reason at all.

    while (valueSet) {
        try {
            wait();

Presumably the problem is that you have your flag the wrong way around.

    if (!valueSet) {
        // ...
    }
    // ...
    valueSet = true;

Presumably the if (should be a while) is intended that valueSet is true, but then you overwrite true with true rather than modifying the variable.

Also of not, Thread.sleep is a static method. It is incredibly misleading (though a common mistake) to call it on an instance.

Thread.currentThread().sleep(/* ... */); // misleading

should be

Thread.sleep(/* ... */);

Upvotes: 3

Related Questions