Java Wait and Notify: IllegalMonitorStateException

2022-08-31 17:32:57

我不完全理解 和 (of) 是如何工作的,因此我被迫将我的尝试缩减到下面的代码部分。waitnotifyObject

主要.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();
  }
}

亚军.java:

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

目前,我在打电话时得到了一个非法的MonitorStateException,但我不明白为什么。从我所看到的, 我需要 同步 ,但是在这样做时,我假设它只会通知一个线程,而这个想法是通知它们。Main.main.wait();Runner.run

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


答案 1

除非当前线程拥有该对象的监视器,否则不能在对象上。为此,您必须在其上执行以下操作: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

答案 2

您正在同时调用两者,并且不使用块。在这两种情况下,调用线程都必须拥有调用方法的监视器上的锁。waitnotifyAllsynchronized

从 文档 ( 和 有类似的文档, 但请参阅 最完整的描述):notifywaitnotifyAllnotify

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

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

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

之后,只有一个线程能够一次实际退出,因为它们都必须再次获取相同的监视器 - 但是所有人都将收到通知,因此,一旦第一个线程退出同步块,下一个线程将获取锁定等。waitnotifyAll


推荐