Java等待和通知:IllegalMonitorStateException

时间:2011-08-19 19:36:57

标签: java multithreading concurrency

我不完全理解waitnotifyObject)的工作方式,因此我不得不减少对下一段代码的尝试

Main.java:

import java.util.ArrayList;

class Main
{
  public static Main main = null;

  public static int numRunners = 4;
  public static ArrayList<Runner> runners = null;

  public static void main(String[] args)
  {
    main = new Main();
  }

  Main()
  {
    runners = new ArrayList<Runner>(numRunners);

    for (int i = 0; i < numRunners; i++)
    {
      Runner r = new Runner();
      runners.add(r);
      new Thread(r).start();
    }

    System.out.println("Runners ready.");
    notifyAll();
  }
}

Runner.java:

class Runner implements Runnable
{
  public void run()
  {
    try
    {
      Main.main.wait();
    } catch (InterruptedException e) {}
    System.out.println("Runner away!");
  }
}

目前我在调用Main.main.wait();时遇到IllegalMonitorStateException,但我不明白为什么。从我所看到的,我需要同步Runner.run,但这样做我认为它只会通知一个线程,当想法是通知所有人。

我看过java.util.concurrent,但我找不到合适的替代品(也许我只是遗漏了一些东西)。

2 个答案:

答案 0 :(得分:59)

除非当前线程拥有该对象的监视器,否则您不能wait()对象。为此,您必须synchronize

class Runner implements Runnable
{
  public void run()
  {
    try
    {
      synchronized(Main.main) {
        Main.main.wait();
      }
    } catch (InterruptedException e) {}
    System.out.println("Runner away!");
  }
}

同样的规则也适用于notify() / notifyAll()

Javadocs for wait()提到这个:

  

此方法只能由作为此对象监视器所有者的线程调用。有关线程成为监视器所有者的方式的说明,请参阅notify方法。

     抛出:      

IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。

来自notify()

  

线程在三个中的一个中成为对象监视器的所有者   方法:

     
      
  • 执行该对象的同步实例方法。
  •   
  • 执行在对象上同步的synchronized语句的正文。
  •   
  • 对于Class类型的对象,通过执行该类的同步静态方法。
  •   

答案 1 :(得分:7)

您在不使用wait阻止的情况下同时呼叫notifyAllsynchronized。在这两种情况下,调用线程必须拥有您调用方法的监视器上的锁。

来自notify的文档(waitnotifyAll有类似的文档,但请参阅notify以获得最全面的描述):

  

此方法只能由作为此对象监视器所有者的线程调用。线程以三种方式之一成为对象监视器的所有者:

     
      
  • 执行该对象的同步实例方法。
  •   
  • 执行在对象上同步的同步语句的主体。
  •   
  • 对于Class类型的对象,通过执行该类的同步静态方法。
  •   
     

一次只能有一个线程拥有对象的监视器。

wait之后,只有一个线程能够实际退出 notifyAll,因为他们都必须再次获得相同的监视器 - 但所有人都将拥有已被通知,所以一旦第一个退出同步块,下一个将获得锁等。