java.lang.IllegalMonitorStateException: (m=null) 无法获得监视器
Posted
技术标签:
【中文标题】java.lang.IllegalMonitorStateException: (m=null) 无法获得监视器【英文标题】:java.lang.IllegalMonitorStateException: (m=null) Failed to get monitor for 【发布时间】:2010-12-05 22:47:06 【问题描述】:为什么会发生这种情况?问题是监视器对象肯定不是空的,但我们仍然经常遇到这个异常:
java.lang.IllegalMonitorStateException: (m=null) Failed to get monitor for (tIdx=60)
at java.lang.Object.wait(Object.java:474)
at ...
引发这种情况的代码是一个简单的池解决方案:
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();
我错过了什么吗?
编辑:异常发生在available.wait();
行。
【问题讨论】:
你能告诉我们源代码中的 474 是哪一行吗? 异常发生在 available.wait();行,但第 474 行来自 java.lang.Object 类。 【参考方案1】:查看 Object.wait 的 javadoc。
特别是“当前线程必须拥有此对象的监视器。”和“[抛出] IllegalMonitorStateException - 如果当前线程不是对象监视器的所有者。”也就是说,您需要在要调用 wait 的对象上进行同步。
所以你的代码应该是:
synchronized (available)
available.wait();
【讨论】:
值得知道:如果available.notify()
发生此异常,请使用相同的模式。
我尝试使用同步函数而不是块来做同样的事情,但它抛出了 IllegalMonitorStateException。这是为什么呢?
Hunter,当你同步一个成员函数时,你会锁定对象——所以this.wait()
应该可以工作。你究竟做了什么?
同步方法确实和this.wait()
一样,但是那些拥有这些方法正在执行的对象的监视器,不是 available
。所以这和synchronized(available)
不一样【参考方案2】:
available.wait();
必须在同步(可用)部分中
【讨论】:
【参考方案3】:您正在从
获得“IllegalMonitorStateException”available.wait()
因为调用 wait() 方法的当前线程不是对象监视器的所有者,即 由“可用”对象引用引用。
线程要成为对象监视器的所有者,有 3 种方式。
-
通过执行该对象的同步实例方法。
通过执行在对象上同步的同步块的主体。
对于 Class 类型的对象,通过执行该类的同步静态方法。
每个场景的简单示例代码。所有三个代码 sn-ps 都是每种类型的单独类,只需复制代码并运行它即可。我在代码中大量添加了 cmets 来解释每种情况下发生的情况。如果它对你来说太多了。只需删除它们以使代码更简洁。
另外,请先阅读 main() 方法中的代码,以了解 threadOne 和 threadTwo。
通过执行该对象的同步实例方法。
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
通过执行在对象上同步的同步块的主体。
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
对于 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
【讨论】:
【参考方案4】:takeObject() 方法必须是同步的,或者,我们必须在这个方法中编写同步块。我希望你应该为此获得编译时异常。
【讨论】:
以上是关于java.lang.IllegalMonitorStateException: (m=null) 无法获得监视器的主要内容,如果未能解决你的问题,请参考以下文章