0

According to How to use wait and notify in Java? I have to synchronized on the same object to call notify.

I have synchronized on the same haveCoffee object. Why I am getting IllegalMonitorStateException when I call the notify method ?

I am Sleeping
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at com.example.concurrent.basic.WaitAndNotify$2.run(WaitAndNotify.java:42)

in the following code:

public class WaitAndNotify {

    public static void main(String[] args) {

        Thread haveCoffee = new Thread() {
            public void run() {
                synchronized (this) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.print("I am awake and ready to have coffee");
                }
            }
        };

        Thread me = new Thread() {
            public void run() {
                synchronized (haveCoffee) {
                    try {
                        System.out.print("I am Sleeping");
                        Thread.sleep(4000);
                        notify();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        haveCoffee.start();
        me.start();
    }
}
Community
  • 1
  • 1
Shivam Sinha
  • 4,924
  • 7
  • 43
  • 65

3 Answers3

2

On the first Thread, you call wait on an object while having its monitor (the object being this haveCoffee).

However, on the second thread, you call notify() on me, while having the monitor of haveCoffee.

This should work:

public class WaitAndNotify {

    public static void main(String[] args) {

        final Thread haveCoffee = new Thread() {
            public void run() {
                synchronized (this) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.print("I am awake and ready to have coffee");
                }
            }
        };

        Thread me = new Thread() {
            public void run() {
                synchronized (haveCoffee) {
                    try {
                        System.out.print("I am Sleeping");
                        Thread.sleep(4000);
                        haveCoffee.notify();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        haveCoffee.start();
        me.start();
    }
}
Yoav Gur
  • 1,366
  • 9
  • 15
  • Thanks that worked. Also http://stackoverflow.com/questions/886722/how-to-use-wait-and-notify-in-java states: To be able to call notify() you need to synchronize on the same object. Is that correct or does it need to synchronize on the object you are going to call wait on ? – Shivam Sinha Mar 20 '16 at 08:47
  • 1
    "To be able to call notify() you need to synchronize on the same object" is correct. You second statement is implicit. Before calling wait() or notify() on a object, you have to synchronize the object. – Ravindra babu Mar 20 '16 at 08:52
  • you should always synchronize on an object, before calling wait/notify on it. Naturally, if you don't wait on the same object you call `notify()` on, you won't get the desired behavior (The waiting code will not be notified). – Yoav Gur Mar 20 '16 at 08:53
  • There is a distinct statement 1: you need to synchronize on the same object ( could be any object) statement 2: synchronize on the object you are going to call wait on. – Shivam Sinha Mar 20 '16 at 08:57
  • If you have to call wait() on a object, it should be synchronized. Generally wait() or notify() calls are just a small part of bigger picture and synchronized protects critical section of big picture. – Ravindra babu Mar 20 '16 at 09:23
1

From oracle documentation page,

public class IllegalMonitorStateException
extends RuntimeException

Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.

Whenever you get this exception, just go through your code and check wait() and notify() calls and the object on which these calls have been invoked. You can easily figure out what went wrong.

EDIT:

wait() or notify() calls have to be invoked on object once you get monitor on that object.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
0

You should be calling

haveCoffee.notify()

instead of just

notify().

If you invoke just notify() it calls the notify() method on the this object which is the second thread me where as you have synchronized on haveCoffee thread and that is the reason for exception you are seeing.

So the code in thread2 me should looks like:

synchronized (haveCoffee) {
    try {
        System.out.print("I am Sleeping");
        Thread.sleep(4000);
        haveCoffee.notify();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}