station
station

Reputation: 7145

Java implementation of Producer Consumer throws java.lang.IllegalMonitorStateException

import java.util.LinkedList;
import java.util.Queue;

class Producer extends PubSub implements Runnable{

    @Override
    public void run() {
        synchronized(queue){
            if (queue.size() == 99){
                try { 
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue.add(2);
            try{
                Thread.sleep(1000);
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            notify();
            }
        }       
}


class Consumer extends PubSub implements Runnable{

    @Override
    public void run() {
        synchronized(queue){
            if(queue.isEmpty()){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }   
            }
            System.out.println(queue.poll());
        }

    }

}
public class PubSub {
    static Integer QUEUE_SIZE = 100;
    Queue<Integer> queue = new LinkedList<Integer>();
    public static void main(String[] args) {
        Producer producer = new Producer();
        Consumer consumer = new Consumer();
        Thread producerThread = new Thread(producer);
        Thread consumerThread = new Thread(consumer);
        producerThread.start();
        consumerThread.start();
        System.out.println("Started both the threads");
    }

}

I am getting a java.lang.IllegalMonitorStateException in the wait() part. I want to know what I am doing wrong here. Any ideas??

The complete exception that I get is as follows.

Exception in thread "Thread-1" Started both the threads
java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at Consumer.run(PubSub.java:36)
    at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at Producer.run(PubSub.java:23)
    at java.lang.Thread.run(Thread.java:745)

Upvotes: 6

Views: 720

Answers (4)

sachin thakur
sachin thakur

Reputation: 101

A thread can call notify() or wait() only on an object on which it has already acquired lock. In your program thread has lock on queue object and then your thread is calling wait on this.

Upvotes: 0

RubioRic
RubioRic

Reputation: 2468

I think that I got your code working ...

As stated by JB Nizet you have to invoke wait and notify on the queue object. I think that such object must be declared static to be shared by Producer and Consumer.

I have included while loops for the code to continue running until the end of time.

Also, an extra notify is needed before Producer and Consumer first wait

Here is your code with that changes included:

import java.util.LinkedList;
import java.util.Queue;

class Producer extends PubSub implements Runnable{

    @Override
    public void run() {
         int index = 0;

         while (true) {
            synchronized(queue){
                while (queue.size() == QUEUE_SIZE){
                    try {
                        System.out.println("Producer waits");
                        queue.notify();
                        queue.wait();
                    } catch (InterruptedException e) {
                       e.printStackTrace();
                    }
                }

                System.out.println("Produce element " + (++index));
                queue.add(2);
                queue.notify();

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e){
                    e.printStackTrace();
                }


            }
        }
    }
}


class Consumer extends PubSub implements Runnable{

     @Override
     public void run() {
         while (true) {
             synchronized(queue) {

                while (queue.isEmpty()){
                    try {
                         System.out.println("Consumer waits");
                         queue.notify();
                         queue.wait();
                    } catch (InterruptedException e) {
                         e.printStackTrace();
                    }
                }

                System.out.println("Consume element " + queue.poll());
                queue.notify();

            }
         }

     }

  }

public class PubSub {
     static Integer QUEUE_SIZE = 100;

     static Queue<Integer> queue = new LinkedList<Integer>();

     public static void main(String[] args) {
          Producer producer = new Producer();
          Consumer consumer = new Consumer();

          Thread producerThread = new Thread(producer);
          Thread consumerThread = new Thread(consumer);

          producerThread.start();
          consumerThread.start();

          System.out.println("Started both the threads");
     }

 }

enter image description here

Upvotes: 2

Aamir Khan
Aamir Khan

Reputation: 3031

Check out the Javadoc for IllegalMonitorStateException

https://docs.oracle.com/javase/7/docs/api/java/lang/IllegalMonitorStateException.html

The exception is thrown when you attempt to wait() (or notify()) on an object of which you don't hold the monitor; You have synchronized on queue, but attempted to wait() on this, which is not the queue, rather the runnable. Changing wait() to queue.wait() and notify() to queue.notify() should work.

Upvotes: 3

JB Nizet
JB Nizet

Reputation: 691775

You're calling wait(), which is equivalent to this.wait(), but you're not holding the monitor of this. You're holding the monitor on queue. So it should be queue.wait(). (same for notify()).

Upvotes: 6

Related Questions