| 方法 | 所屬類 | 調用前提 | 行為 | 釋放鎖 |
wait() | Object | 持有對象監視器鎖(在 synchronized 內) | 釋放鎖,進入等待集,阻塞直到:被 notify/notifyAll、超時、中斷、虛假喚醒 | 是 |
notify() | Object | 持有對象監視器鎖 | 隨機喚醒一個在等待集的線程,移入入口集競爭鎖 | 否(退出 synchronized 才釋放) |
notifyAll() | Object | 持有對象監視器鎖 | 喚醒所有等待集線程,全部移入入口集 | 否 |
關鍵規則:同一把鎖
wait/notify 必須在同一個對象鎖上調用。線程 A synchronized(obj) { obj.wait(); },線程 B synchronized(obj) { obj.notify(); }。鎖對象不一致 → IllegalMonitorStateException。
等待-喚醒流程圖解
線程 A (消費者) 線程 B (生產者)
synchronized(obj) { synchronized(obj) {
while (queue.empty()) { produce();
obj.wait(); ──────→ obj.notify(); // 唤醒 A
} }
consume(); // B 退出 synchronized 釋放鎖
} // A 從入口集獲取鎖,繼續執行
經典生產者消費者:有界隊列實現
class BoundedBuffer<T> {
private final List<T> buffer = new ArrayList<>();
private final int capacity;
public BoundedBuffer(int capacity) { this.capacity = capacity; }
// 生產者調用
public synchronized void put(T item) throws InterruptedException {
while (buffer.size() == capacity) { // while 防虛假喚醒
wait(); // 釋放鎖,等待空槽
}
buffer.add(item);
notifyAll(); // 唤醒所有消費者
}
// 消費者調用
public synchronized T take() throws InterruptedException {
while (buffer.isEmpty()) {
wait(); // 釋放鎖,等待數據
}
T item = buffer.remove(0);
notifyAll(); // 唤醒所有生產者
return item;
}
}
關鍵細節
- while 而非 if:防止虛假喚醒(Spurious Wakeup)——線程在無 notify 情況下被喚醒,JVM 允許。
while (condition) wait() 確保條件真正滿足才繼續。
- notifyAll 優於 notify:多生產多消費場景,notify 可能喚醒同類線程(如喚醒另一生產者),導致無效切換;notifyAll 喚醒所有,由線程自行檢查條件。
- 同步方法隱式鎖:
synchronized 方法鎖住 this,等價於 synchronized(this)。
進階:Lock + Condition 替代 Object 監視器
JDK 5+ java.util.concurrent.locks.Condition 提供更強大的等待/通知機制:
class BoundedBufferV2<T> {
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final List<T> buffer = new ArrayList<>();
private final int capacity;
public void put(T item) throws InterruptedException {
lock.lock();
try {
while (buffer.size() == capacity) notFull.await();
buffer.add(item);
notEmpty.signal(); // 精確喚醒消費者
} finally { lock.unlock(); }
}
public T take() throws InterruptedException {
lock.lock();
try {
while (buffer.isEmpty()) notEmpty.await();
T item = buffer.remove(0);
notFull.signal(); // 精確喚醒生產者
return item;
} finally { lock.unlock(); }
}
}
Condition 優勢
- 一把鎖綁定多個 Condition(
notFull/notEmpty),精確喚醒目標線程組,避免無效競爭。
- 支持
awaitUninterruptibly()、awaitNanos()、awaitUntil() 多種等待模式。
- 可中斷/不可中斷靈活控制。
實戰避坑清單