java.lang.IllegalMonitorStateException: (m=null) Failed to get monitor for
Why may this happen? The thin开发者_如何转开发g is that monitor object is not null for sure, but still we get this exception quite often:
java.lang.IllegalMonitorStateException: (m=null) Failed to get monitor for (tIdx=60)
at java.lang.Object.wait(Object.java:474)
at ...
The code that provokes this is a simple pool solution:
public Object takeObject() {
Object obj = internalTakeObject();
while (obj == null) {
try {
available.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
obj = internalTakeObject();
}
return obj;
}
private Object internalTakeObject() {
Object obj = null;
synchronized (available) {
if (available.size() > 0) {
obj = available.keySet().iterator().next();
available.remove(obj);
synchronized (taken) {
taken.put(obj, Boolean.valueOf(true));
}
}
}
return obj;
}
public void returnObject(Object obj) {
synchronized (taken) {
taken.remove(obj);
}
synchronized (available) {
if (available.size() < size) {
available.put(obj, Boolean.valueOf(true));
available.notify();
}
}
}
Am I missing something?
EDIT: The exception happens in available.wait();
line.
See the javadoc for Object.wait.
in particular "The current thread must own this object's monitor." and "[throws] IllegalMonitorStateException - if the current thread is not the owner of the object's monitor." That is, you need to synchronize on the object you are going to call wait on.
so your code should be:
synchronized (available) {
available.wait();
}
available.wait();
must be in a synchronized(available) section
You are getting the "IllegalMonitorStateException" from
available.wait()
because the current thread that invokes the wait() method is not the owner of the Object's monitor that is referenced by the "available" object reference.
For a thread to become the owner of an object's monitor, there are 3 ways.
- By executing a synchronized instance method of that object.
- By executing the body of a synchronized block that synchronizes on the object.
- For objects of type Class by executing a synchronized static method of that class.
Simple sample code for each scenario. All three code snippets are separate classes for each type, just copy the code and run it. I added comments heavily into the code to explain what's happening in each case. If it's too many comments for you. just delete them to make the code more concise.
Also, read the code in main() method first to get an idea about threadOne and threadTwo first.
By executing a synchronized instance method of that object.
import static java.lang.System.out; public class SynchronizedInstanceMethodClass { synchronized void synchronizedInstanceMethod() { // threadOne acquire the monitor for "this" and continue. try { out.println("EVENT #1 threadOne is about to strat waiting on the " +"monitor it already has - [\"this\"]...."); this.wait(); // The threadOne already have the monitor for "this", // just release the monitor and go and wait threadOne. out.println("EVENT #3 Notify received and continue execution..."); } catch (InterruptedException interruptedException) { interruptedException.printStackTrace(); } } synchronized void notifierForAllThreads() { // threadTwo acquire the monitor for "this", // which was released by threadOne when it went to waiting and contine. out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) " +" waiting on the monitor of -[\"this\"]...."); this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all // threads waiting on "this" and releases the monitor } public static void main(String [] args) { SynchronizedInstanceMethodClass mc = new SynchronizedInstanceMethodClass(); Thread threadOne = new Thread(() -> {mc.synchronizedInstanceMethod();}); Thread threadTwo = new Thread(() -> {mc.notifierForAllThreads();}); threadOne.start(); // Start the waiting of Thread one threadTwo.start(); // Notify the waiting threadOne } }
By executing the body of a synchronized block that synchronizes on the object.
import static java.lang.System.out; public class SynchronizedBlockClass { void synchronizedBlockInstanceMethod() { synchronized (this) { // threadOne acquire the monitor for "this" and continue. try { out.println("EVENT #1 threadOne is about to strat waiting on the " +"monitor it already has - [\"this\"]...."); this.wait(); // The threadOne already have the monitor for "this", // just release the monitor and go and wait threadOne. out.println("EVENT #3 Notify received and continue execution..."); } catch (InterruptedException interruptedException) { interruptedException.printStackTrace(); } } } void synchronizedBlockNotifierForAllThreads() { synchronized (this) { // threadTwo acquire the monitor for "this", // which was released by threadOne when it went to waiting and continue. out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) " +" waiting on the monitor of -[\"this\"]...."); this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all // threads waiting on "this" and releases the monitor } } public static void main(String [] args) { SynchronizedBlockClass mc = new SynchronizedBlockClass(); Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();}); Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();}); threadOne.start(); // Start the waiting of Thread one threadTwo.start(); // Notify the waiting threadOne } }
For objects of type Class by executing a synchronized static method of that class.
import static java.lang.System.out; public class StaticClassReferenceClass { void synchronizedBlockInstanceMethod() { synchronized (StaticClassReferenceClass.class) { // threadOne acquire the monitor for class literal and continue. try { out.println("EVENT #1 threadOne is about to strat waiting on the " +"monitor it already has - [StaticClassReferenceClass.class]...."); StaticClassReferenceClass.class.wait(); // The threadOne already have the monitor for the class literal, // So it just release the monitor and go and wait. out.println("EVENT #3 Notify received and continue execution..."); } catch (InterruptedException interruptedException) { interruptedException.printStackTrace(); } } } void synchronizedBlockNotifierForAllThreads() { synchronized (StaticClassReferenceClass.class) { // threadTwo acquire the monitor for the class literal, // which was released by threadOne when it went to waiting. out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) " +" waiting on the monitor of -[StaticClassReferenceClass.class]...."); StaticClassReferenceClass.class.notifyAll(); // threadTwo who owns the monitor on the class literal notifies all // threads waiting on it and releases the monitor } } public static void main(String [] args) { StaticClassReferenceClass mc = new StaticClassReferenceClass(); Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();}); Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();}); threadOne.start(); // Start the waiting of Thread one threadTwo.start(); // Notify the waiting threadOne } }
takeObject() method must be synchronized or, we have to write synchronized block inside this method. I hope u should get compile time exception for this.
精彩评论