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

Java线程生产者-消费者问题代码输出逻辑疑惑咨询

关于Java生产者-消费者模型的输出逻辑困惑

我对这段Java生产者-消费者问题的代码输出逻辑存在困惑,我的理解步骤是:

  • 生产者线程启动,随后消费者线程启动。
  • 生产者线程向列表添加1个元素,调用notify()但此时无等待线程,列表长度为1。
  • 生产者线程再添加1个元素,调用notify()仍无等待线程,列表长度为2。
  • 由于列表长度达到上限2,生产者线程执行wait()进入等待状态。
  • 消费者线程开始运行,移除1个元素后调用notify(),此时列表长度变为1。

我的疑惑点:步骤5中,消费者线程调用notify()后,是会唤醒等待的生产者线程使其添加新元素,还是会继续移除元素直到列表为空?从实际输出看是后者,但我原本认为应该唤醒生产者线程,请纠正我的理解偏差。

代码示例

public class Main {

    public static void main(String[] args) {
        Processor processor = new Processor();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    processor.producer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    processor.consumer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();
    }

}


class Processor {

    private List<Integer> list = new ArrayList<>();
    private static final int UPPER_LIMIT = 2;
    private static final int LOWER_LIMIT = 0;
    private int value = 0;

    private final Object lock = new Object();

    public void producer() throws InterruptedException {
        synchronized(lock) {
            while (true) {
                if (list.size() == UPPER_LIMIT) {
                    System.out.println("Waiting for removing items...");
                    // lock.wait() because we synchronized on the `lock`
                    lock.wait(); // if just wait() means we are waiting on the Processor itself
                } else {
                    System.out.println("Adding: " + value);
                    list.add(value);
                    value++;
                    // we can call the notify - because the other thread will be notified
                    // only when it is in a waiting state
                    lock.notify();
                    Thread.sleep(1000);
                }
            }
        }
    }

    public void consumer() throws InterruptedException {
        synchronized(lock) {
            while (true) {
                if (list.size() == LOWER_LIMIT) {
                    System.out.println("Waiting for adding items...");
                    lock.wait(); 
                } else {
                    System.out.println("Removing: " + list.remove(list.size() - 1));
                    lock.notify();
                    Thread.sleep(1000);
                }
            }
        }
    }

}

实际输出

// Output
Adding: 0
Adding: 1
Waiting for removing items...
Removing: 1
Removing: 0
Waiting for adding items...
Adding: 2
Adding: 3
Waiting for removing items...
Removing: 3
Removing: 2
Waiting for adding items...
Adding: 4
Adding: 5
Waiting for removing items...
Removing: 5
Removing: 4

逻辑纠正

核心原因在于线程唤醒后不会立即抢占锁,以及synchronized块的执行逻辑:

  1. 当消费者线程开始运行时,它已经持有了lock对象的锁——因为生产者调用wait()后会主动释放锁,消费者才能进入自己的synchronized块。
  2. 消费者移除第一个元素后调用notify(),这个操作只是通知等待队列里的生产者线程:「你可以准备抢锁了」,但当前消费者线程还没释放锁——它会继续执行完当前循环的剩余逻辑(包括Thread.sleep(1000)),然后回到while(true)的循环判断。
  3. 此时列表长度为1,不等于下限0,所以消费者会继续执行移除操作,直到列表为空,才会触发list.size() == LOWER_LIMIT的条件,调用wait()释放锁。
  4. 只有当消费者释放锁后,之前被唤醒的生产者线程才有机会获取锁,继续执行添加元素的逻辑。

简单总结:notify()只是唤醒等待线程,不会强制当前线程立刻释放锁。当前线程会把synchronized块内的循环逻辑执行到需要释放锁的节点(也就是调用wait()),才会交出锁的控制权。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 09:30:36