java.lang.IllegalMonitorStateException异常:跨线程notify()调用问题
解决Java中调用notify()时的IllegalMonitorStateException异常
你遇到的这个IllegalMonitorStateException异常,本质原因很清晰:调用notify()或者wait()方法时,当前线程必须持有该对象的对象监视器锁——换句话说,你得先通过synchronized块或方法“锁住”目标对象,才能调用它的通知/等待方法,否则JVM就会抛出这个异常来警告你。
结合你的场景(主类、生产者、消费者是三个独立类,且用了LinkedBlockingQueue),我给你两种针对性的解决方案:
方案一:手动实现等待/通知机制(不依赖BlockingQueue内置能力)
首先你需要一个所有线程共享的锁对象,把它传递给生产者和消费者类,确保两者操作的是同一个锁。然后在调用notify()/wait()时,必须包裹在synchronized(锁对象)的代码块里。
举个完整的代码示例:
主类 queueCheck
public class queueCheck { public static void main(String[] args) throws InterruptedException { BlockingQueue<testObjectClass> queue = new LinkedBlockingQueue<testObjectClass>(); Object sharedLock = new Object(); // 定义共享锁对象 Producer producer = new Producer(queue, sharedLock); Consumer consumer = new Consumer(queue, sharedLock); new Thread(producer).start(); new Thread(consumer).start(); } }
Producer 类
public class Producer implements Runnable { private BlockingQueue<testObjectClass> queue; private Object sharedLock; // 构造方法传入队列和共享锁 public Producer(BlockingQueue<testObjectClass> queue, Object sharedLock) { this.queue = queue; this.sharedLock = sharedLock; } @Override public void run() { try { // 生产一个对象并放入队列 testObjectClass obj = new testObjectClass(); queue.put(obj); // 必须在同步块内调用notify(),确保当前线程持有锁 synchronized (sharedLock) { sharedLock.notify(); // 通知消费者线程 } } catch (InterruptedException e) { // 规范处理线程中断 Thread.currentThread().interrupt(); } } }
Consumer 类
public class Consumer implements Runnable { private BlockingQueue<testObjectClass> queue; private Object sharedLock; public Consumer(BlockingQueue<testObjectClass> queue, Object sharedLock) { this.queue = queue; this.sharedLock = sharedLock; } @Override public void run() { try { // 在同步块内等待通知 synchronized (sharedLock) { sharedLock.wait(); // 等待生产者的通知 } // 取出队列中的对象进行消费 testObjectClass obj = queue.take(); // 这里添加你的消费逻辑 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
方案二:直接利用BlockingQueue的内置机制(更推荐)
其实你已经用到了LinkedBlockingQueue,这个类本身就是为生产者-消费者场景设计的线程安全队列,它内部已经封装了锁和等待/通知逻辑,完全不需要你手动调用notify()或wait()!
比如:
queue.put(obj):当队列满时,生产者线程会自动阻塞,直到有消费者取出元素;queue.take(obj):当队列空时,消费者线程会自动阻塞,直到有生产者放入元素;
用这个方案的话,代码会简洁很多,还能避免手动处理锁带来的错误:
简化的Producer类
public class Producer implements Runnable { private BlockingQueue<testObjectClass> queue; public Producer(BlockingQueue<testObjectClass> queue) { this.queue = queue; } @Override public void run() { try { while (true) { // 持续生产对象 testObjectClass obj = new testObjectClass(); queue.put(obj); System.out.println("生产了一个对象"); Thread.sleep(1000); // 模拟生产耗时 } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
简化的Consumer类
public class Consumer implements Runnable { private BlockingQueue<testObjectClass> queue; public Consumer(BlockingQueue<testObjectClass> queue) { this.queue = queue; } @Override public void run() { try { while (true) { // 自动等待直到有对象可以消费 testObjectClass obj = queue.take(); System.out.println("消费了一个对象"); Thread.sleep(1500); // 模拟消费耗时 } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
最后总结
- 如果你一定要手动调用
notify()/wait(),务必记住:只有在持有对象锁的情况下(也就是在synchronized块/方法内),才能调用该对象的这两个方法; - 既然已经使用了
BlockingQueue,强烈推荐直接用它的put()和take()方法,既简洁又能避免锁相关的异常。
内容的提问来源于stack exchange,提问作者guruprabhus
相关产品推荐
相关产品推荐

