0

I have a piece of code which is giving IllegalMonitorException while calling notifyAll. While enQueue(), thread add the data and throws illegalMonitorException.

BlockingQueue.class :

public class BlockingQueue {
private Queue<Integer> queue = new LinkedList<>();
private int maxCount;
private Lock lock = new ReentrantLock();

BlockingQueue(int maxCount){
    this.maxCount=maxCount;
}

public  void enQueue(int d) throws InterruptedException {
    lock.lock();
    if(queue.size() >= maxCount){
        System.out.println("going to wait enqueu "+Thread.currentThread().getName() +" size "+queue.size());
        lock.wait();
    }
    System.out.println(" Adding "+d);
    queue.add(d);
    lock.notify();
    lock.unlock();
}

public  Integer deQueue() throws InterruptedException {
    lock.lock();
    if(queue.size()==0){
        System.out.println("going to wait dequeue "+Thread.currentThread().getName()+" size "+queue.size());
        lock.wait();
    }
    int data = queue.remove();
    lock.notify();
    lock.unlock();
    return data;
}}

Main.Class :

 public class Main {
public static void main(String args[]){
    BlockingQueue queue=new BlockingQueue(10);
    Producer p = new Producer(queue);
    Consumer c = new Consumer(queue);

    Thread t1=new Thread(c,"Consumer");
    Thread t2=new Thread(p, "producer");

    t1.start();
    t2.start();
}}

Producer.class :

 public class Producer implements Runnable {
private BlockingQueue q;
Producer(BlockingQueue qu){
    this.q=qu;
}

public Integer generateWork() throws InterruptedException {
    return new Random().nextInt(100 );
}

@Override
public void run() {
    for(int i =0; i<100; i++){
        try {
            Thread.sleep(100);
            q.enQueue(generateWork());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}}

Consumer.class :

public class Consumer implements Runnable {

private BlockingQueue queue;
Consumer(BlockingQueue q){
    this.queue=q;
}

public void consume(int data){
    System.out.println(" consume "+data);
}

@Override
public void run() {
    for(int i=0; i < 100; i++){
        try {
            Thread.sleep(1000);
            consume(queue.deQueue());
        } catch (InterruptedException e) {
           System.out.println("interrupted");
        }
    }
}}

Output :

Adding 94

Exception in thread "producer" java.lang.IllegalMonitorStateException

at java.lang.Object.notify(Native Method)
at BlockingQueue.enQueue(BlockingQueue.java:23)
at Producer.run(Producer.java:20)
at java.lang.Thread.run(Thread.java:748)
7
  • 1
    Could you post full code that can be ran to reproduce the issue? Commented Jan 25, 2020 at 6:45
  • Hey.. i have updated the code. I dont want to use condition. :/ Commented Jan 25, 2020 at 6:56
  • 1
    If you're using Lock then you have to use Condition. But why are you hesitant to use Condition? Commented Jan 25, 2020 at 7:02
  • @Slaw it is not compulsory to use Condition with Lock but yeah its a great combo. Commented Jan 25, 2020 at 7:08
  • 1
    @YogeshBadke It is if you want to use the API correctly. While your answer may work, one should either use synchronized with Object's wait/notify or Lock with Condition's await/signal. Using synchronized (lock) where lock is an instance of java.util.concurrent.locks.Lock is a code smell. Commented Jan 25, 2020 at 7:10

1 Answer 1

0

Following code fixes the issue

public class BlockingQueue {
    private Queue<Integer> queue = new LinkedList<>();
    private int maxCount;
    private Lock lock = new ReentrantLock();

    BlockingQueue(int maxCount) {
        this.maxCount = maxCount;
    }

    public void enQueue(int d) throws InterruptedException {
        lock.lock();
        if (queue.size() >= maxCount) {
            System.out.println("going to wait enqueu " + Thread.currentThread().getName() + " size " + queue.size());
            waitInternal();
        }
        System.out.println(" Adding " + d);
        queue.add(d);
        notifyInternal();
        lock.unlock();
    }

    public Integer deQueue() throws InterruptedException {
        lock.lock();
        if (queue.size() == 0) {
            System.out.println("going to wait dequeue " + Thread.currentThread().getName() + " size " + queue.size());
            waitInternal();
        }
        int data = queue.remove();
        notifyInternal();
        lock.unlock();
        return data;
    }

    private void waitInternal() throws InterruptedException {
        synchronized (lock) {
            lock.wait();
        }
    }

    private void notifyInternal() throws InterruptedException {
        synchronized (lock) {
            lock.notify();
        }
    }
}

Explanation: You were calling wait and notify from the non-synchronized block which is not allowed. When you call either of these, you should take a monitor lock on that object. In this case lock.

Here is a great read on why must wait/notify always be in a synchronized block https://stackoverflow.com/a/2779565/1891456

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.