0

How do I notify a thread from one object to another in the below program without using synchronized methods in the following producer and consumer problem.

I am using a queue class for the put and get methods and using wait() and notify() in the run() method of Producer class and Consumer class.

My goal is to use the wait() and notify() methods in the Producer class and Consumer class and not use them in the Queue class.

It is giving an IllegalMonitorStateException.

Program:

package threads;

class Queue{
    int num;

    int get(int number)
    {

        System.out.println("The Consumer "+number+" got "+num);
        return num;
    }

    void put(int n,int number)
    {

        this.num=n;
        System.out.println("The producer "+number+" put "+this.num);

    }
}

public class producerandconsumer{
    boolean flag=false;
class Producer implements Runnable{
    Queue q;
    int number;
    Producer(Queue q,int number)
    {
        this.q=q;
        this.number = number;
        new Thread(this,"Producer").start();
    }

    public void run()
    {
        for(int i=0;i<10;i++)
        {
            while(flag)
                try{
                    wait();
                }
                catch(InterruptedException e){
                    System.out.println("InterruptedException caught ");
                }
            q.put(i,number);
            flag=true;
            notify();
        }
    }

}

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

    public void run()
    {
        for(int i=0;i<10;i++)
        {
            while(!flag)
                try{
                    wait();
                    }
                    catch(InterruptedException e){
                        System.out.println("InterruptedException caught ");
                    }
                flag=false;
                notify();
                q.get(number);
        }
    }
}



public static void main(String[] args) {
    // TODO Auto-generated method stub
    producerandconsumer pc= new producerandconsumer();
    Queue q=new Queue();
    pc.new Producer(q,1);
    pc.new Consumer(q,1);


}

}

Output of the Program :It is giving an IllegalMonitorStateException.

 The producer 1 put 0 Exception in thread "Producer" 
 java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at threads.producerandconsumer$Producer.run(producerandconsumer.java:48)
at java.lang.Thread.run(Unknown Source)

Exception in thread "Consumer" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at threads.producerandconsumer$Consumer.run(producerandconsumer.java:76)
at java.lang.Thread.run(Unknown Source)
DavidPostill
  • 7,734
  • 9
  • 41
  • 60
  • 2
    Use a BlockingQueue. You don't need to use wait and notify when using a BlockingQueue. The Queue will wait and notify threads. The consumer simply gets items from the queue, and the queue blocks it until there is an item available. The producer simply puts items in the queue, and is blocked by the queue until there is space left in the queue (if it's bounded). – JB Nizet Oct 27 '14 at 07:13
  • The object shared between threads is Queue, so you have to synchronize there, not in Producer/Consumer! – isnot2bad Oct 27 '14 at 08:05
  • will use Blocking Queue..thanks @ JB Nizer and isnot2bad. – Raghav Kishan Oct 27 '14 at 11:09

2 Answers2

3

Methods wait and notify must be called inside synchronized block. That's why you get illegelMonitorStateException.

Sergii Lagutin
  • 10,561
  • 1
  • 34
  • 43
  • oh..ok..thanks :) can i synchronize the run method..? – Raghav Kishan Oct 27 '14 at 07:09
  • i got the exception removed . can i explicitly notify a thread? – Raghav Kishan Oct 27 '14 at 07:10
  • To keep object's monitor you need synchronized block on this object. Synchronized method is wrong idea. – Sergii Lagutin Oct 27 '14 at 07:12
  • i need to use the wait and notify methods in the classes implementing Runnable , so how do i go about it..?? – Raghav Kishan Oct 27 '14 at 07:30
  • I really don't see reasons to use wait/notify methods. If you want just synchronize queue access use synchronized block with queue object. – Sergii Lagutin Oct 27 '14 at 07:47
  • @Sergey I assume it is necessary to wait when queue is empty or full. – isnot2bad Oct 27 '14 at 08:07
  • @Sergey Consumer and Producer don't synchronize on the same object. So just wrapping notify/wait in a synchrnoized block won't help. It just fixes the exception. – isnot2bad Oct 27 '14 at 08:36
  • @isnot2bad Consumer and Producer use same queue. So they could synchonize on it easily. But I like your solution. I agree that synchonization must be inside queue but outside. – Sergii Lagutin Oct 27 '14 at 08:42
  • @Sergey Yes, they use the same queue, but both, `Producer` and `Consumer` don't call `wait` and `notify` on the `queue` but on themselves instead! So they are not communicating! Instead, they both will wait forever after the first call to `wait`. – isnot2bad Oct 27 '14 at 08:47
  • @isnot2bad You're right. I implicitly mean when you synchronize on some object you call wait/notify methods on it :) – Sergii Lagutin Oct 27 '14 at 08:52
2

The state shared between threads is your Queue class, so you have to make it thread-safe by using proper synchronization. It is not a good idea to put synchronization code in your Producer and Consumer as this requires additional communication between them and does not scale.

Below there is a simple example of a synchronized integer queue that can hold one single int only (similar to your Queue). It blocks when take is called on an empty queue and when put is called on a queue that's full.

Note that you should rather use existing synchronized data structures like implementations of BlockingQueue for real-world applications!

public class IntQueue {
    int data;
    boolean filled = false;

    public synchronized int take() throws InterruptedException
    {
        while (!filled) { // wait for filled condition
            wait();
        }

        filled = false; // set not-filled condition
        notifyAll(); // notify (other) waiting threads

        return data;
    }

    public synchronized void put(int data) throws InterruptedException
    {
        while (filled) { // wait for not-filled condition
            wait();
        }

        filled = true; // set filled condition
        notifyAll(); // notify (other) waiting threads

        this.data = data;
    }
}

Using this queue you can have an arbitrary number of producers and consumers that do not need any further synchronization:

static final IntQueue queue = new IntQueue();
static final int POISON_PILL = -1; // stops Consumer

class Producer implements Runnable {
    public void run() {
        try {
            for(int i = 0; i < 100; i++) {
                System.out.println("producing " + i);
                queue.put(i);
            }
        } catch (InterruptedException ex) { /* done */ }
    }
}

class Consumer implements Runnable {
    public void run() {
        try {
            int n = queue.take();
            // poison pill causes Consumer to stop
            while (n != POISON_PILL) {
                System.out.println("consuming " + i);
                n = queue.take();
            }
        } catch (InterruptedException ex) { /* done */ }
    }
}

public static void main() throws Exception {
    // create threads
    Thread p1 = new Thread(new Producer());
    Thread p2 = new Thread(new Producer());
    Thread c = new Thread(new Consumer());

    // start threads
    p1.start();
    p2.start();
    c.start();

    // wait for producers to complete
    p1.join();
    p2.join();

    // queue poison pill to stop consumer
    queue.put(POISON_PILL);

    // wait for consumer to complete
    c.join();
}
isnot2bad
  • 24,105
  • 2
  • 29
  • 50