Java报错”IllegalMonitorStateException”的原因以及解决办法

  • Post category:Java

首先我们要了解一下Java中Wait/Notify机制。

Java中的Wait/Notify机制是一种线程间的协作方式,用于控制多个线程之间的执行顺序与互斥访问共享资源。

当一个线程调用Object.wait()方法时,它会进入阻塞状态,等待其他线程调用Object.notify()方法来唤醒它。而其他线程在调用Object.notify()方法时,会唤醒被阻塞的线程,将其从阻塞状态转移至就绪状态。

但是,在使用Wait/Notify机制时,我们需要注意以下两点:

  1. Wait/Notify方法只能在同步块或同步方法内部调用(即已经获得了对象的监视器/Monitor),否则会报”IllegalMonitorStateException”异常。

  2. 在调用wait()方法后,当前线程会释放对象的监视器,直到它被唤醒后重新获得监视器的锁。

那么我们来看一下第一个示例:

public class WaitNotifyTest {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        obj.wait();
    }
}

运行这段代码会抛出IllegalMonitorStateException异常,因为在调用obj.wait()时没有获取目标对象obj的监视器。

解决方法是将代码放在同步块或同步方法内部,并在调用wait()/notify()方法前获得监视器的锁:

public class WaitNotifyTest {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        synchronized (obj) {
            obj.wait();
        }
    }
}

在这个示例中,我们使用了synchronized关键字来获得obj的监视器锁,并在同步块内部调用wait()方法,避免了IllegalMonitorStateException异常的抛出。

接下来我们看第二个示例:

public class WaitNotifyTest {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        obj.notify();
    }
}

在这个示例中,调用obj.notify()方法不会抛出IllegalMonitorStateException异常,但是它也不能正常地唤醒其他线程。

因为唤醒其他线程需要在持有对象监视器锁的情况下进行。所以需要将代码放在同步块或同步方法内部,并在调用notify()方法前获得监视器的锁。

public class WaitNotifyTest {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        synchronized (obj) {
            obj.notify();
        }
    }
}

这样,我们就可以正确地唤醒其他线程了。

综上所述,IllegalMonitorStateException异常的产生原因是在调用wait()/notify()方法时没有获得目标对象的监视器锁。解决方法是将代码放在同步块或同步方法内部,并在调用wait()/notify()方法前获得监视器的锁。