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异常。