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

Java双类同步问题:生产者notify后消费者仍等待求助

问题根源:锁对象不统一!

嘿,这问题太典型了——你写的Producer和Consumer各自用自己的实例对象当锁,导致notify()根本喊不醒对方!

为啥会这样?

你仔细看代码就懂了:

  • Producer里的synchronized(this),锁的是Producer p这个实例
  • Consumer里的synchronized(this),锁的是Consumer c这个实例

notify()方法的作用是唤醒在当前锁对象上等待的线程。所以Producer调用notify(),只能叫醒在Producer对象上wait的线程(也就是它自己),Consumer在自己的锁上睡得死死的,根本听不到这个通知,可不就一直卡在while(buffer.isEmpty()) wait();这里嘛!

怎么解决?

用同一个共享对象作为两个线程的锁就行——这里最适合的就是你们共用的Buffer实例,毕竟两个线程的操作都是围绕它来的。

修改后的代码示例:

Producer类修改:

public class Producer extends Thread {
    private Buffer buffer;
    private int total;

    public Producer(Buffer buffer, int total) {
        this.buffer = buffer;
        this.total = total;
    }

    public void run() {
        int count = 0;
        while(count < total) {
            synchronized(buffer) { // 改用buffer作为锁对象
                try {
                    while(buffer.isFull()) {
                        buffer.wait(); // 在buffer锁上等待
                    }
                    int val = (int)(Math.random()*100);
                    buffer.insert(val);
                    System.out.println("Producer添加元素:" + val + ",当前buffer大小:" + buffer.getSize());
                    buffer.notify(); // 唤醒在buffer锁上等待的线程
                    count++;
                } catch(InterruptedException e) {
                    Thread.currentThread().interrupt(); // 恢复中断状态
                }
            }
            // 可选:模拟生产延迟
            try {
                Thread.sleep(100);
            } catch(InterruptedException e) {}
        }
    }
}

Consumer类修改:

public class Consumer extends Thread {
    private Buffer buffer;
    private int total;

    public Consumer(Buffer buffer, int total) {
        this.buffer = buffer;
        this.total = total;
    }

    public void run() {
        int count = 0;
        while(count < total) {
            synchronized(buffer) { // 同样用buffer作为锁对象
                try {
                    while(buffer.isEmpty()) {
                        buffer.wait(); // 在buffer锁上等待
                    }
                    int val = buffer.remove();
                    System.out.println("Consumer移除元素:" + val + ",当前buffer大小:" + buffer.getSize());
                    buffer.notify(); // 唤醒在buffer锁上等待的线程
                    count++;
                } catch(InterruptedException e) {
                    Thread.currentThread().interrupt(); // 恢复中断状态
                }
            }
            // 可选:模拟消费延迟
            try {
                Thread.sleep(200);
            } catch(InterruptedException e) {}
        }
    }
}

额外提醒

  1. 你用while循环判断buffer的空/满状态是完全正确的!别改成if,因为线程被唤醒后可能会遇到虚假唤醒(比如多个线程等待时,notify唤醒了一个,但此时buffer状态又不符合条件了),while循环会再次检查条件,确保逻辑安全。
  2. 处理InterruptedException时,最好调用Thread.currentThread().interrupt()恢复中断状态,避免后续逻辑忽略中断信号。

这样修改后,Producer和Consumer共用同一个锁对象,notify就能准确唤醒对方,线程间的协作就正常啦!

内容的提问来源于stack exchange,提问作者N. Colostate

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:34:26