java中可用synchronized配合wait()/notifyall()实现生产者-消费者模型:共享缓冲区需synchronized保护,生产者满时wait、添加后notifyall,消费者空时wait、移除后notifyall,须用while防虚假唤醒且notifyall避免遗漏唤醒。

Java 中可以通过 synchronized 关键字配合 wait() 和 notifyAll()(或 notify())来实现经典的生产者-消费者模型,核心在于共享缓冲区的线程安全访问与线程间协作。
共享资源:带容量限制的缓冲区
定义一个线程安全的容器(如 ArrayList),用 synchronized 保护所有读写操作,并维护当前大小。缓冲区满时生产者等待,空时消费者等待。
- 使用
private final List<string> buffer = new ArrayList();</string>作为共享队列 - 用
private final int capacity = 5;控制最大数量 - 所有访问该列表的方法都加
synchronized,确保同一时刻只有一个线程操作
生产者:先检查、再添加、后通知
生产者线程在同步块中判断缓冲区是否已满;若满则调用 wait() 释放锁并进入等待状态;否则添加元素,并调用 notifyAll() 唤醒可能等待的消费者。
-
while (buffer.size() == capacity)—— 必须用while而非if,防止虚假唤醒 - 添加后调用
notifyAll(),因为多个消费者可能都在等,仅唤醒一个可能导致死锁 - 示例逻辑:
buffer.add("item" + count++); notifyAll();
消费者:先检查、再移除、后通知
消费者同理:在同步块中检查缓冲区是否为空;为空则 wait();否则移除元素并 notifyAll() 唤醒生产者。
-
while (buffer.isEmpty())同样必须是循环,避免被错误唤醒后直接消费空集合 - 移除推荐用
buffer.remove(0)(队列式)或buffer.remove(buffer.size()-1)(栈式),按需选择 - 消费后也要
notifyAll(),确保生产者有机会继续生产
注意事项与常见陷阱
这个模型看似简单,但几个细节直接影响正确性:
-
wait()和notifyAll()必须在synchronized方法或代码块内调用,否则抛IllegalMonitorStateException - 永远不要用
notify()替代notifyAll(),除非你完全确定只有一个线程在等待且类型明确(比如一对一场景),否则极易遗漏唤醒 - 避免在同步块中执行耗时操作(如 I/O、复杂计算),否则会阻塞其他线程,降低吞吐量
- 如果需要更灵活的控制(如超时等待、公平锁、多条件等待),建议升级到
java.util.concurrent包中的Lock和Condition
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











