代码之家  ›  专栏  ›  技术社区  ›  Andrey Adamovich

java.lang.IllegalMonitorStateException:(m=null)无法获取的监视器

  •  34
  • Andrey Adamovich  · 技术社区  · 16 年前

    为什么会发生这种情况?问题是monitor对象肯定不是空的,但我们仍然经常遇到这种异常:

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

    4 回复  |  直到 16 年前
        1
  •  74
  •   tgdavies    16 年前

    有关Object.wait,请参阅javadoc。

    因此,您的代码应该是:

    synchronized (available) {
        available.wait();
    }
    
        2
  •  7
  •   Mariusz Jamro    13 年前

    available.wait(); 必须在同步(可用)部分中

        3
  •  1
  •   G 1    7 年前

    您正在从中获取“非法监视器状态异常”

    available.wait()
    

    由“可用”对象引用引用。

    1. 通过执行该对象的同步实例方法。
    2. 通过执行在对象上同步的同步块的主体。

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

    另外,首先阅读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. 对于类类型的对象,执行该类的同步静态方法。

      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
  •  0
  •   prasad    12 年前

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