You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
        }
    }
}

最后总结

  1. 如果你一定要手动调用notify()/wait(),务必记住:只有在持有对象锁的情况下(也就是在synchronized块/方法内),才能调用该对象的这两个方法;
  2. 既然已经使用了BlockingQueue,强烈推荐直接用它的put()和take()方法,既简洁又能避免锁相关的异常。

内容的提问来源于stack exchange,提问作者guruprabhus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:38:43