Java线程间协作:基于wait与notify的生产者-消费者模式实现
线程协作的必要性
在多线程编程中,多个线程往往需要协同完成某项任务。例如,一个线程负责生成数据(生产者),另一个线程负责处理这些数据(消费者)。若没有有效的通信机制,可能导致资源浪费或逻辑错误,比如消费者在无数据时持续尝试读取,或生产者在缓冲区已满时仍强行写入。 为解决这类问题,Java提供了线程间的等待/唤醒机制,使线程能够根据条件暂停执行,并在条件满足时被其他线程唤醒,从而实现有序协作。核心方法概述
Java通过以下三个定义在Object类中的方法支持线程通信:
- wait():调用该方法的线程会释放当前持有的对象锁,并进入等待状态,直到被其他线程唤醒。
- notify():随机唤醒一个正在等待该对象锁的线程,使其从等待队列转入就绪状态。
- notifyAll():唤醒所有等待该对象锁的线程,由系统调度器决定哪个线程获得锁并继续执行。
这些方法必须在synchronized块或方法中调用,且操作的对象必须是同一把锁,否则会抛出IllegalMonitorStateException异常。
为何定义在Object类?
由于Java中每个对象都可作为同步监视器(即锁),而等待和唤醒操作是针对"某个对象的锁"进行的,因此将wait、notify等方法定义在Object类中是最合理的做法——所有对象天然具备这一能力。
wait() 与 sleep() 的关键区别
| 特性 | wait() | sleep() |
|---|---|---|
| 所属类 | Object | Thread |
| 是否释放锁 | 是 | 否 |
| 使用环境 | 必须在synchronized中使用 | 任意位置 |
| 唤醒方式 | notify()/notifyAll() | 超时自动恢复或中断
实际案例:食物生产与消费模型
下面通过一个典型的生产者-消费者场景演示线程协作机制。共享资源类
public class SharedResource {
private boolean hasProduct = false; // 标记是否有产品可供消费
public synchronized void produce() {
while (hasProduct) {
try {
wait(); // 若已有产品,则生产者等待
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
for (int i = 1; i <= 5; i++) {
System.out.println("【生产】第 " + i + " 个商品");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
hasProduct = true;
notify(); // 通知消费者可以开始消费
}
public synchronized void consume() {
while (!hasProduct) {
try {
wait(); // 若无产品,则消费者等待
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
for (int i = 1; i <= 5; i++) {
System.out.println("【消费】第 " + i + " 个商品");
try {
Thread.sleep(400);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
hasProduct = false;
notify(); // 通知生产者可以继续生产
}
}
生产者线程
public class Producer implements Runnable {
private final SharedResource resource;
public Producer(SharedResource resource) {
this.resource = resource;
}
@Override
public void run() {
while (!Thread.interrupted()) {
resource.produce();
}
}
}
消费者线程
public class Consumer implements Runnable {
private final SharedResource resource;
public Consumer(SharedResource resource) {
this.resource = resource;
}
@Override
public void run() {
while (!Thread.interrupted()) {
resource.consume();
}
}
}
测试主类
public class ProducerConsumerDemo {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread producerThread = new Thread(new Producer(resource), "Producer");
Thread consumerThread = new Thread(new Consumer(resource), "Consumer");
producerThread.start();
consumerThread.start();
}
}
运行输出示例
【生产】第 1 个商品 【生产】第 2 个商品 【生产】第 3 个商品 【生产】第 4 个商品 【生产】第 5 个商品 【消费】第 1 个商品 【消费】第 2 个商品 【消费】第 3 个商品 【消费】第 4 个商品 【消费】第 5 个商品 【生产】第 1 个商品 【生产】第 2 个商品 ...
从输出可见,生产与消费交替进行,确保了资源的有效利用和线程间的协调运行。
总结
通过wait()和notify()机制,Java实现了高效的线程间通信。这种协作模式广泛应用于缓冲区管理、任务队列、资源池等并发场景中,是构建稳定多线程应用的基础工具之一。