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块的执行逻辑:
- 当消费者线程开始运行时,它已经持有了
lock对象的锁——因为生产者调用wait()后会主动释放锁,消费者才能进入自己的synchronized块。 - 消费者移除第一个元素后调用
notify(),这个操作只是通知等待队列里的生产者线程:「你可以准备抢锁了」,但当前消费者线程还没释放锁——它会继续执行完当前循环的剩余逻辑(包括Thread.sleep(1000)),然后回到while(true)的循环判断。 - 此时列表长度为1,不等于下限0,所以消费者会继续执行移除操作,直到列表为空,才会触发
list.size() == LOWER_LIMIT的条件,调用wait()释放锁。 - 只有当消费者释放锁后,之前被唤醒的生产者线程才有机会获取锁,继续执行添加元素的逻辑。
简单总结:notify()只是唤醒等待线程,不会强制当前线程立刻释放锁。当前线程会把synchronized块内的循环逻辑执行到需要释放锁的节点(也就是调用wait()),才会交出锁的控制权。
内容的提问来源于stack exchange,提问作者Jessica
相关产品推荐
相关产品推荐

