java.lang.IllegalMonitorStateException:(M = NULL)无法获得监视器

问题描述 投票:34回答:4

为什么会出现这种情况?问题是,监测对象是不是null肯定的,但我们仍然可以得到这个异常经常:

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();线。

java multithreading locking pool
4个回答
71
投票

见的Object.wait的Javadoc。

尤其是“当前线程必须拥有该对象的监视器。”和“[引发]抛出:IllegalMonitorStateException - 如果当前线程不是这个对象监视器的所有者。”也就是说,你需要你要打电话等待的对象同步。

所以你的代码应该是:

synchronized (available) {
    available.wait();
}

7
投票

available.wait();必须以同步的(可用的)部分


0
投票

takeObject()方法必须是同步的或,我们必须写这方法内的同步块。我希望你应该得到的编译时间例外这一点。


0
投票

你正在从“抛出:IllegalMonitorStateException”

available.wait()

因为调用wait()方法的当前线程不是一个由“可用”的对象引用所引用的对象监视器的拥有者。

对于一个线程成为对象监视器的拥有者,有3种方式。

  1. 通过执行对象的同步实例方法。
  2. 通过执行同步块,该对象上同步的主体上。
  3. 用于通过执行该类的同步静态方法Class类型的对象。

每个方案的简单示例代码。所有这三个代码片段是为每种类型的单独的类,只需要复制该代码并运行它。我添加了注释大举进入的代码来解释发生的事情在每种情况下。如果这是你太多的评论。只是删除它们,使代码更简洁。

此外,阅读在main()方法的代码获取最threadOne和threadTwo一个理念先行。

  1. 通过执行对象的同步实例方法。 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 } }
  2. 通过执行同步块,该对象上同步的主体上。 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 } }
  3. 用于通过执行该类的同步静态方法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 } }
© www.soinside.com 2019 - 2024. All rights reserved.