问题分析
java.lang.IllegalMonitorStateException
是一个运行时异常,通常在操作线程同步代码时触发。这类异常的根本原因是线程尝试执行同步操作(如 wait()
、notify()
、notifyAll()
)时,未获取到目标对象的监视器锁。
报错原因
- 未获取锁
- 调用
wait()
、notify()
、notifyAll()
方法的对象需要持有其监视器锁,但线程没有同步到该对象。
- 调用
- 同步块问题
- 没有在同步块(
synchronized
)中调用同步方法。
- 没有在同步块(
- 错误的锁对象
- 使用了错误的对象作为同步锁,导致没有持有正确的监视器。
示例报错代码
以下代码会触发 IllegalMonitorStateException
:
public class IllegalMonitorStateDemo {
public static void main(String[] args) {
Object lock = new Object();
// 在未同步的情况下调用 wait() 方法
try {
lock.wait(); // 会抛出 IllegalMonitorStateException
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
错误信息:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.base/java.lang.Object.wait(Native Method)
at IllegalMonitorStateDemo.main(IllegalMonitorStateDemo.java:8)
解决思路
-
确保同步块的使用
:
- 调用
wait()
、notify()
或notifyAll()
时,必须将相关代码放入synchronized
块中。
- 调用
-
检查锁对象
:
- 确保
synchronized
块的对象与调用同步方法的对象一致。
- 确保
-
避免嵌套锁问题
:
- 保证线程持有的锁不会被无效释放或遗漏。
-
理解锁的作用范围
:
- 确认哪些线程需要等待和通知,并正确管理监视器锁。
解决方法
示例修正代码 1:正确使用同步块
public class FixedMonitorStateDemo {
public static void main(String[] args) {
Object lock = new Object();
// 在同步块中调用 wait 方法
synchronized (lock) {
try {
System.out.println("Thread is waiting...");
lock.wait(); // 正确用法
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
示例修正代码 2:正确使用 notify()
public class NotifyExample {
public static void main(String[] args) {
Object lock = new Object();
Thread waitingThread = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Waiting thread is waiting...");
lock.wait();
System.out.println("Waiting thread is resumed.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread notifyingThread = new Thread(() -> {
synchronized (lock) {
System.out.println("Notifying thread is notifying...");
lock.notify(); // 通知正在等待的线程
}
});
waitingThread.start();
try {
Thread.sleep(1000); // 确保 wait 先执行
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyingThread.start();
}
}
输出结果:
Waiting thread is waiting...
Notifying thread is notifying...
Waiting thread is resumed.
总结
- 正确理解同步方法的锁机制:
- 调用
wait()
、notify()
、notifyAll()
时,必须获取对象的监视器锁。
- 调用
- 使用同步块包裹相关操作:
- 始终在
synchronized
块中操作共享资源。
- 始终在
- 确认锁对象的一致性:
- 确保锁对象是共享的且唯一的。
- 排查竞争条件:
- 在多线程环境中,避免未按顺序调用
wait()
和notify()
方法。
- 在多线程环境中,避免未按顺序调用
通过这些方法,IllegalMonitorStateException
异常问题可以轻松解决。按照上述流程排查,逐步验证和修复代码,让你的多线程程序更加健壮。