Java Wait and Notify: IllegalMonitorStateException

109,072

Solution 1

You can't wait() on an object unless the current thread owns that object's monitor. To do that, you must synchronize on it:

class Runner implements Runnable
{
  public void run()
  {
    try
    {
      synchronized(Main.main) {
        Main.main.wait();
      }
    } catch (InterruptedException e) {}
    System.out.println("Runner away!");
  }
}

The same rule applies to notify()/notifyAll() as well.

The Javadocs for wait() mention this:

This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.

Throws:

IllegalMonitorStateException – if the current thread is not the owner of this object's monitor.

And from notify():

A thread becomes the owner of the object's monitor in one of three ways:

  • By executing a synchronized instance method of that object.
  • By executing the body of a synchronized statement that synchronizes on the object.
  • For objects of type Class, by executing a synchronized static method of that class.

Solution 2

You're calling both wait and notifyAll without using a synchronized block. In both cases the calling thread must own the lock on the monitor you call the method on.

From the docs for notify (wait and notifyAll have similar documentation but refer to notify for the fullest description):

This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:

  • By executing a synchronized instance method of that object.
  • By executing the body of a synchronized statement that synchronizes on the object.
  • For objects of type Class, by executing a synchronized static method of that class.

Only one thread at a time can own an object's monitor.

Only one thread will be able to actually exit wait at a time after notifyAll as they'll all have to acquire the same monitor again - but all will have been notified, so as soon as the first one then exits the synchronized block, the next will acquire the lock etc.

Share:
109,072
skeggse
Author by

skeggse

Updated on July 09, 2022

Comments

  • skeggse
    skeggse almost 2 years

    I don't completely understand how wait and notify (of Object) work, and as a result I'm forced to slim down my attempts into the following section of code.

    Main.java:

    import java.util.ArrayList;
    
    class Main
    {
      public static Main main = null;
    
      public static int numRunners = 4;
      public static ArrayList<Runner> runners = null;
    
      public static void main(String[] args)
      {
        main = new Main();
      }
    
      Main()
      {
        runners = new ArrayList<Runner>(numRunners);
    
        for (int i = 0; i < numRunners; i++)
        {
          Runner r = new Runner();
          runners.add(r);
          new Thread(r).start();
        }
    
        System.out.println("Runners ready.");
        notifyAll();
      }
    }
    

    Runner.java:

    class Runner implements Runnable
    {
      public void run()
      {
        try
        {
          Main.main.wait();
        } catch (InterruptedException e) {}
        System.out.println("Runner away!");
      }
    }
    

    Currently I get an IllegalMonitorStateException when calling Main.main.wait();, but I don't understand why. From what I can see, I need to synchronize Runner.run, but in doing so I assume it would only notify one thread, when the idea is to notify them all.

    I've looked at java.util.concurrent, but I can't find a suitable replacement (maybe I'm just missing something).

  • gonglong
    gonglong over 9 years
    wait() would release object monitor before blocking its thread, so it would not block other threads calling notify.
  • user695022
    user695022 over 6 years
    For people linked here, the object you call wait() on must be the same object you're synchronizing on. Calling x.wait() in a synchronized(y) block will yield the same exception.