Resolving IllegalMonitorStateException In Java

In this tutorial, we will learn IllegalMonitorStateException and when it is thrown with examples. We will also see how we can prevent our code from throwing this exception along with some of the best practices to follow in multithreaded applications.

1. Java IllegalMonitorStateException class

IllegalMonitorStateException class present in java.lang package and has been there since Java version 1.0. It extends RuntimeException class; hence, it’s an unchecked exception and needs not to be declared in a method’s or a constructor’s throws clause.

Constructors defined in this class:

  • IllegalMonitorStateException(): Creates an instance of the IllegalMonitorStateException class, setting null as its message.
  • IllegalMonitorStateException(String message): Creates an instance of the IllegalMonitorStateException class, using the specified message.

2. What causes IllegalMonitorStateException

For inter-thread communication (in which 2 threads communicate with each other), threads have to use wait(), notify() and notifyAll() methods. Thread class inherits these methods from the Object class.

A Thread should acquire the object’s lock to call these methods on that object. If a Thread tries to call wait(), notify() and notifyAll() methods on an object without acquiring that object’s lock or outside of the synchronized block, the program throws IllegalMonitorStateException.

Let’s now look at an example of how a Thread raises IllegalMonitorStateException. In this example, we are going to create a Waiting Thread and a Notifying Thread.

  • WaitingThread calls the wait() method and enters into a waiting state until some other Thread calls notify() method and notifies it.
  • NotifyingThread calls the notify() method and notifies the waiting Thread to start processing again.
public class IllegalMonitorStateExceptionDemo
{

    //This object is used for synchronization among threads.
    public final static Object obj = new Object();
    
    public static class WaitingThread extends Thread {

        @Override
        public void run() {
            try {
                   //Calling wait() method outside of synchronized area
                    obj.wait();    // Raises IllegalMonitorStateException
                 }
                catch (InterruptedException ex) {
                    System.out.println(Thread.currentThread().getName() + " gets Interrupted");
                }
        }
    }
     
    public static class NotifyingThread extends Thread {

        @Override
        public void run() {
          try {
                    // Thread sleep for 5 sec
                    Thread.sleep(5000);
                    // Calling notify() outside of synchronized area                 
                    obj.notify();         // Raises IllegalMonitorStateException
                }
                catch (InterruptedException ex) {
                    System.err.println(Thread.currentThread().getName() + " gets Interrupted");
                }
        }
    }
}

Try running both threads to verify.

public static void main(String[] args) {
    WaitingThread waitingThread = new WaitingThread();
    NotifyingThread notifyingThread  = new NotifyingThread();

    waitingThread.start();
    notifyingThread.start();
}

We will get the IllegalMonitorStateException in the console.

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread is not owner
	at java.base/java.lang.Object.wait(Native Method)
	at java.base/java.lang.Object.wait(Object.java:338)
	at com.howtodoinjava.concurrency.IllegalMonitorStateExceptionDemo $WaitingThread.run(IllegalMonitorStateExceptionDemo.java:23)

Exception in thread "Thread-1" java.lang.IllegalMonitorStateException: current thread is not owner
	at java.base/java.lang.Object.notify(Native Method)
	at com.howtodoinjava.concurrency.IllegalMonitorStateExceptionDemo $NotifyingThread.run(IllegalMonitorStateExceptionDemo.java:39)

3. Resolving IllegalMonitorStateException

IllegalMonitorStateException resolves when a Thread calls wait(), notify() and notifyAll() methods on an object after acquiring that object’s lock means it should call these methods inside synchronized block only.

In the above example, if both Waiting & Notifying Threads call wait() and notify() in synchronized block then we won’t get IllegalMonitorStateException in our code.

So the correct way of calling these methods without this exception is as below,

  public static class WaitingThread extends Thread {

        @Override
        public void run() {
            try {
                    //Obtain lock using the synchronized keyword
                    synchronized(obj){
                        
                       //Calling wait() inside synchronized block
                        obj.wait();
                    }
                  }
                catch (InterruptedException ex) {
                    System.err.println(Thread.currentThread().getName() + " gets Interrupted");
                }
        }
  }

public static class NotifyingThread extends Thread {

        @Override
        public void run() {
          try {
                    Thread.sleep(5000);

                    //Obtain lock first
                     synchronized(obj){  
                        //Calling notify() inside synchronized block
                        obj.notify();
                     }
                }
                catch (InterruptedException ex) {
                    System.err.println(Thread.currentThread().getName() + " gets Interrupted");
                }
        }
}

Now if we run the program, it completes successfully.

4. Best Practices

  • Since Java version 1.5, we have java.util.concurrent package which contains various new concurrency classes and frameworks that make our work easy while working in a multithreaded environment.
  • For inter-thread communication, instead of using the old way of using wait() and notify() method, we can make use of BlockingQueue instead present in java.util.concurrent package.
  • BlockingQueue Interface represents a queue that is thread-safe to put into and take elements from while 2 Threads are communicating with each other, which in turn avoids any IllegalMonitorStateException as well.
  • Lock Interface and ReentrantLock class provide more control over the concurrency as compared with synchronized block. Using it, a Thread can try for a lock without waiting, eliminating the chances of a deadlock situation.
  • We can use other classes like CountDownLatch, CyclicBarrier, Exchanger, Phaser, SynchronousQueue in order to work with multiple threads in a multithreaded application.

5. Conclusion

In this article, we learned about IllegalMonitorStateException, what are the causes for this and how to prevent it in our code. We have also seen some of the best practices for using new concurrency classes that can help in avoiding the IllegalMonitorStateException.

Happy Learning !!

Sourcecode on Github

Leave a Reply

0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.