程间通信
多线程协作需要通信机制,实现等待/唤醒、通知/响应等交互。
wait/notify/notifyAll
基本用法
Java
public class WaitNotifyDemo {
private final Object lock = new Object();
private boolean ready = false;
// 等待线程
public void waitForReady() throws InterruptedException {
synchronized (lock) {
while (!ready) { // 循环检查条件
lock.wait(); // 释放锁并等待
}
// 条件满足后继续执行
}
}
// 通知线程
public void setReady() {
synchronized (lock) {
ready = true;
lock.notify(); // 唤醒一个等待线程
// lock.notifyAll(); // 唤醒所有等待线程
}
}
}
必须 synchronized:wait/notify/notifyAll 必须在同步代码块中调用,否则抛 IllegalMonitorStateException。
wait vs sleep
| 特性 | wait() | sleep() |
|---|---|---|
| 释放锁 | ✅ 释放 | ❌ 不释放 |
| 所属类 | Object | Thread |
| 唤醒方式 | notify/notifyAll | 时间到期或 interrupt |
| 使用位置 | 同步代码块 | 任意位置 |
notify vs notifyAll
| 方法 | 说明 | 适用场景 |
|---|---|---|
| notify() | 随机唤醒一个 | 只有一个等待线程 |
| notifyAll() | 唤醒所有等待线程 | 多个等待线程 |
推荐 notifyAll:避免唤醒不合适的线程导致死等。
生产者-消费者模式
Java
public class ProducerConsumer {
private final Queue<Integer> queue = new LinkedList<>();
private final int capacity = 10;
private final Object lock = new Object();
// 生产者
public void produce(int item) throws InterruptedException {
synchronized (lock) {
while (queue.size() == capacity) {
lock.wait(); // 缓冲区满,等待
}
queue.add(item);
System.out.println("生产:" + item);
lock.notifyAll(); // 通知消费者
}
}
// 消费者
public int consume() throws InterruptedException {
synchronized (lock) {
while (queue.isEmpty()) {
lock.wait(); // 缓冲区空,等待
}
int item = queue.poll();
System.out.println("消费:" + item);
lock.notifyAll(); // 通知生产者
return item;
}
}
}
while 循环检查条件:防止虚假唤醒,被唤醒后条件可能仍不满足。
Condition(ReentrantLock)
Condition 提比 wait/notify 更灵活的等待/唤醒机制:
Java
public class ConditionDemo {
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final Queue<Integer> queue = new LinkedList<>();
private final int capacity = 10;
public void produce(int item) throws InterruptedException {
lock.lock();
try {
while (queue.size() == capacity) {
notFull.await(); // 等待非满条件
}
queue.add(item);
notEmpty.signal(); // 通知非空条件
} finally {
lock.unlock();
}
}
public int consume() throws InterruptedException {
lock.lock();
try {
while (queue.isEmpty()) {
notEmpty.await(); // 等待非空条件
}
int item = queue.poll();
notFull.signal(); // 通知非满条件
return item;
} finally {
lock.unlock();
}
}
}
Condition vs wait/notify
| 特性 | Condition | wait/notify |
|---|---|---|
| 条件数量 | 多个 Condition | 单个 wait/notify |
| 精确唤醒 | signal() 唤醒指定条件 | notifyAll() 唤醒所有 |
| 所属 | ReentrantLock | synchronized |
Condition 优势:多个条件独立等待唤醒,避免不相关线程被唤醒。
volatile 通信
volatile 保证可见性,适合简单通信:
Java
public class VolatileDemo {
private volatile boolean running = true;
// 工作线程
public void work() {
while (running) { // 读取最新值
// 工作逻辑
}
System.out.println("线程停止");
}
// 停止线程
public void stop() {
running = false; // 立即可见
}
}
volatile 适用:状态标志位、单例双重检查锁。不保证原子性。
join() 等待线程结束
Java
Thread thread = new Thread(() -> {
// 执行任务
});
thread.start();
thread.join(); // 等待 thread 结束
// join 后继续执行
要点总结
- wait/notify/notifyAll 用于 synchronized 同步通信
- wait() 释放锁并等待,sleep() 不释放锁
- notify() 随机唤醒一个,notifyAll() 唤醒所有
- 必须在 synchronized 中调用 wait/notify
- while 循环检查条件防止虚假唤醒
- Condition 支持多个条件,精确唤醒
- volatile 保证可见性,适合状态标志
- join() 等待线程结束
📝 发现内容有误?点击此处直接编辑