多线程里的wait方法和notify方法介绍
时间: 2025-07-28 22:06:14 浏览: 12
<think>我们首先介绍多线程中的wait()和notify()方法。这两个方法是Java中Object类的方法,用于线程间的协作(通信)。它们必须在同步代码块或同步方法中使用,因为它们需要操作对象的监视器(锁)。1.wait()方法:当线程调用一个对象的wait()方法时,该线程会释放该对象的锁,并进入等待状态(WAITING),直到其他线程调用同一个对象的notify()或notifyAll()方法,或者被中断。2.notify()方法:唤醒在此对象监视器上等待的单个线程。如果有多个线程都在等待,则选择其中一个唤醒(具体哪个取决于线程调度器)。被唤醒的线程将尝试重新获取对象的锁,然后从wait()方法返回继续执行。3.notifyAll()方法:唤醒在此对象监视器上等待的所有线程。这些线程将竞争获取对象的锁,然后从wait()方法返回继续执行。注意:使用wait()和notify()时必须持有该对象的锁(即在synchronized块内),否则会抛出IllegalMonitorStateException。下面我们用一个经典的生产者-消费者问题来演示wait()和notify()的使用。示例代码:生产者-消费者模型我们创建一个固定大小的缓冲区,生产者向缓冲区放入数据,消费者从缓冲区取出数据。当缓冲区满时,生产者等待;当缓冲区空时,消费者等待。我们使用一个队列(这里用LinkedList)作为缓冲区,并设置最大容量。</think>### 多线程中的 `wait()` 和 `notify()` 方法详解
`wait()` 和 `notify()` 是 Java 多线程编程中用于线程间协作的核心方法(定义在 `java.lang.Object` 类中),它们通过**对象监视器(Monitor)** 实现线程的等待/唤醒机制,需在 `synchronized` 代码块中使用。
#### 核心概念
1. **`wait()`**
- 释放对象锁,使当前线程进入等待状态(WAITING)
- 线程会一直阻塞,直到其他线程调用同一对象的 `notify()`/`notifyAll()`
2. **`notify()`**
- 随机唤醒一个在该对象上等待的线程(若有多个等待线程)
- **不释放锁**,被唤醒的线程需重新竞争锁
3. **`notifyAll()`**
- 唤醒所有在该对象上等待的线程
- 所有被唤醒线程竞争锁,只有一个能获取锁继续执行
---
### 代码示例:生产者-消费者模型
```java
import java.util.LinkedList;
import java.util.Queue;
public class WaitNotifyDemo {
private static final int MAX_SIZE = 5;
private final Queue<Integer> buffer = new LinkedList<>();
private final Object lock = new Object();
// 生产者
public void produce() throws InterruptedException {
int value = 0;
while (true) {
synchronized (lock) {
// 缓冲区满时等待
while (buffer.size() == MAX_SIZE) {
System.out.println("缓冲区满,生产者等待...");
lock.wait(); // 释放锁并等待
}
System.out.println("生产: " + value);
buffer.offer(value++);
lock.notifyAll(); // 唤醒所有等待线程(消费者)
Thread.sleep(500); // 模拟生产耗时
}
}
}
// 消费者
public void consume() throws InterruptedException {
while (true) {
synchronized (lock) {
// 缓冲区空时等待
while (buffer.isEmpty()) {
System.out.println("缓冲区空,消费者等待...");
lock.wait(); // 释放锁并等待
}
int value = buffer.poll();
System.out.println("消费: " + value);
lock.notifyAll(); // 唤醒所有等待线程(生产者)
Thread.sleep(1000); // 模拟消费耗时
}
}
}
public static void main(String[] args) {
WaitNotifyDemo demo = new WaitNotifyDemo();
// 启动生产者线程
new Thread(() -> {
try { demo.produce(); }
catch (InterruptedException e) { e.printStackTrace(); }
}).start();
// 启动消费者线程
new Thread(() -> {
try { demo.consume(); }
catch (InterruptedException e) { e.printStackTrace(); }
}).start();
}
}
```
#### 代码解释:
1. **共享资源**
- `buffer`:固定大小的队列(最大容量 `MAX_SIZE=5`)
- `lock`:作为同步监视器对象
2. **生产者逻辑**
- 当缓冲区满时 (`buffer.size() == MAX_SIZE`),调用 `lock.wait()` 释放锁并等待
- 生产数据后调用 `lock.notifyAll()` 唤醒可能等待的消费者线程
3. **消费者逻辑**
- 当缓冲区空时 (`buffer.isEmpty()`),调用 `lock.wait()` 释放锁并等待
- 消费数据后调用 `lock.notifyAll()` 唤醒可能等待的生产者线程
4. **关键点**
- 使用 `while` 而非 `if` 检查条件(避免虚假唤醒问题)
- `wait()`/`notify()` 必须在 `synchronized` 块内调用
- `notifyAll()` 比 `notify()` 更安全(避免线程永久等待)
---
### 注意事项
1. **锁对象一致性**
`wait()` 和 `notify()` 必须使用**同一个对象**的监视器锁(示例中的 `lock` 对象)。
2. **虚假唤醒(Spurious Wakeup)**
线程可能在没有调用 `notify()` 的情况下被唤醒,因此条件检查必须使用 `while` 循环而非 `if`。
3. **优先使用 `notifyAll()`**
`notify()` 随机唤醒单个线程,可能导致死锁;`notifyAll()` 唤醒所有线程更安全。
4. **替代方案**
现代 Java 开发中更推荐使用 `java.util.concurrent` 包中的高级工具(如 `BlockingQueue`、`Lock`、`Condition`)。
---
### 执行流程示意图
```
生产者线程 缓冲区 消费者线程
---------- -------- -----------
1. 获取锁
2. 检查缓冲区是否满
└─ 满 → wait() → 释放锁
└─ 未满 → 生产数据
3. notifyAll() → 唤醒消费者
4. 释放锁
数据流动
↓
1. 获取锁
2. 检查缓冲区是否空
└─ 空 → wait() → 释放锁
└─ 非空 → 消费数据
3. notifyAll() → 唤醒生产者
4. 释放锁
```
阅读全文
相关推荐



















