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

  • Post category:Java

Java中的IllegalMonitorStateException异常表示线程试图在非法的监视器状态下等待、通知或者进行唤醒操作。这个异常通常会在锁定对象的监视器解除锁定时出现,即notify和notifyAll方法被调用时,没有获取该对象的锁而调用这些方法就会抛出异常。

解决此异常的方法就是在调用wait()、notify()或notifyAll()函数之前必须先获得该对象的监视器,而获得监视器通常需要使用synchronized关键字。

下面来看两个示例:

示例一:

public class MyThread extends Thread {
    private Object lock;

    public MyThread(Object lock) {
        this.lock = lock;
    }

    public void run() {
        try {
            synchronized (lock) {
                lock.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Object lock = new Object();
        MyThread myThread = new MyThread(lock);
        myThread.start();
        try {
            Thread.sleep(1000);
            synchronized (lock) {
                lock.notify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

上述代码创建了一个线程和一个锁对象,并在MyThread线程内部使用wait()方法等待通知,并在主线程中执行notify()方法唤醒该线程。但是由于没有获取该对象的锁就使用了wait()和notify()方法,会抛出IllegalMonitorStateException异常。

解决方法是在调用wait()和notify()方法之前必须先获取该对象的锁,即在使用wait()和notify()方法时必须使用synchronized关键字锁定该对象。

修改后的代码如下:

public class MyThread extends Thread {
    private Object lock;

    public MyThread(Object lock) {
        this.lock = lock;
    }

    public void run() {
        try {
            synchronized (lock) {
                lock.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Object lock = new Object();
        MyThread myThread = new MyThread(lock);
        myThread.start();
        try {
            Thread.sleep(1000);
            synchronized (lock) {
                lock.notify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

修改代码后,即先对对象进行锁定再使用wait()和notify()方法,这样就不会抛出IllegalMonitorStateException异常了。

示例二:

public class MyThread extends Thread {
    private Object lock;

    public MyThread(Object lock) {
        this.lock = lock;
    }

    public void run() {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + "获得锁");
        }

        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + "再次获得锁");
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Object lock = new Object();
        MyThread myThread = new MyThread(lock);
        myThread.start();
    }
}

上述代码创建了一个线程和一个锁对象,MyThread线程在两个代码块中分别获取了该锁,但是两个代码块之间没有释放该锁,导致再次获取锁的时候抛出了IllegalMonitorStateException异常。

解决方法是保持锁的使用和释放是成对的,即每次获取锁都必须对其进行正确的释放,以避免抛出IllegalMonitorStateException异常。修改后的代码如下:

public class MyThread extends Thread {
    private Object lock;

    public MyThread(Object lock) {
        this.lock = lock;
    }

    public void run() {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + "获得锁");
        }

        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + "再次获得锁");
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Object lock = new Object();
        MyThread myThread = new MyThread(lock);
        myThread.start();
    }
}

修改后,即在获取锁后对锁进行了正确的释放,不会再抛出IllegalMonitorStateException异常。