synchronized实现生产者-消费者需用同一锁对象协调操作,配合wait()和notifyall()实现等待唤醒;所有共享状态读写须在synchronized块中,条件判断必须用while循环防虚假唤醒。

synchronized 是 Java 中最基础的同步机制,可以用来实现线程安全的生产者-消费者模型。它的核心在于:**用同一个锁对象协调生产和消费操作,配合 wait() 和 notifyAll() 实现线程间等待与唤醒**。
共享缓冲区必须是线程安全的
生产者和消费者操作的是同一份资源(比如一个队列),这个资源必须被保护起来:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 所有对共享状态的读写(如判断是否满/空、添加/移除元素)都必须在
synchronized块或方法中进行 - 锁对象要唯一且一致,推荐使用缓冲区自身(如
queue)作为锁,避免锁错对象 - 不能只同步“添加”或“移除”动作,而忽略条件判断——否则会出现虚假唤醒或状态不一致
用 wait() 和 notifyAll() 控制线程协作
仅靠 synchronized 无法让线程“等条件满足再继续”,必须搭配 wait() 和 notifyAll():
-
wait()必须在synchronized块内调用,它会释放锁并挂起当前线程,直到被唤醒 -
notifyAll()唤醒所有等待该锁的线程(推荐用它,而不是notify(),避免信号丢失) - 必须用
while循环检查条件(不是if!),防止虚假唤醒(spurious wakeup)
典型代码结构示例
以下是一个基于 LinkedList 的简单实现:
class Buffer {
private final LinkedList<integer> queue = new LinkedList();
private final int capacity = 5;
public void produce(int item) throws InterruptedException {
synchronized (queue) {
while (queue.size() == capacity) {
queue.wait(); // 缓冲区满,生产者等待
}
queue.addLast(item);
System.out.println("Produced: " + item + ", size=" + queue.size());
queue.notifyAll(); // 唤醒可能等待的消费者
}
}
public int consume() throws InterruptedException {
synchronized (queue) {
while (queue.isEmpty()) {
queue.wait(); // 缓冲区空,消费者等待
}
int item = queue.removeFirst();
System.out.println("Consumed: " + item + ", size=" + queue.size());
queue.notifyAll(); // 唤醒可能等待的生产者
return item;
}
}
}
</integer>
注意事项和常见陷阱
- 不要在 synchronized 外调用
wait()或notify(),会抛IllegalMonitorStateException - 不要用
Thread.sleep()替代wait(),它不释放锁,也无法被其他线程唤醒 - 多个生产者/消费者时,
notify()可能只唤醒同类型线程(比如只唤醒另一个生产者),导致死锁,所以坚持用notifyAll() - 如果用
synchronized方法,锁对象是this;若缓冲区是私有成员,建议显式锁在该成员上,更清晰可控
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










