Java Wait and Notify: IllegalMonitorStateException
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
Throws:notify
method for a description of the ways in which a thread can become the owner of a monitor.
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.
skeggse
Updated on July 09, 2022Comments
-
skeggse almost 2 years
I don't completely understand how
wait
andnotify
(ofObject
) 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 synchronizeRunner.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 over 9 yearswait() would release object monitor before blocking its thread, so it would not block other threads calling notify.
-
user695022 over 6 yearsFor people linked here, the object you call
wait()
on must be the same object you're synchronizing on. Callingx.wait()
in asynchronized(y)
block will yield the same exception.