【问题标题】:java.lang.IllegalMonitorStateException: (m=null) Failed to get monitor forjava.lang.IllegalMonitorStateException: (m=null) 无法获得监视器
【发布时间】: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 类。

标签: java multithreading locking pool


【解决方案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 种方式。

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

    每个场景的简单示例代码。所有三个代码 sn-ps 都是每种类型的单独类,只需复制代码并运行它即可。我在代码中大量添加了 cmets 来解释每种情况下发生的情况。如果它对你来说太多了。只需删除它们以使代码更简洁。

    另外,请先阅读 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
          }
      
      }
      

    【讨论】:

      【解决方案4】:

      takeObject() 方法必须是同步的,或者,我们必须在这个方法中编写同步块。我希望你应该为此获得编译时异常。

      【讨论】:

        猜你喜欢
        • 2012-03-10
        • 1970-01-01
        • 2016-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        • 2016-10-08
        相关资源
        最近更新 更多