Java中的wait和notify機制
基礎概念
在Java中,wait()
和notify()
是Object
類的原生方法,用于實現線程間的協作:
wait()
- 使當前線程釋放對象鎖并進入等待狀態
- 必須在
synchronized
代碼塊內調用 - 語法:
obj.wait()
或obj.wait(long timeout)
- 線程狀態變化:RUNNING → WAITING
notify()
- 隨機喚醒一個在該對象上等待的線程
notifyAll()
喚醒所有等待線程- 同樣必須在
synchronized
代碼塊內調用
// 生產者-消費者示例
class Buffer {private int data;private boolean available = false;public synchronized void produce(int value) {while (available) wait(); // 等待消費者取走數據data = value;available = true;notifyAll(); // 喚醒消費者}public synchronized int consume() {while (!available) wait(); // 等待生產者寫入數據available = false;notifyAll(); // 喚醒生產者return data;}
}
執行流程
graph LRA[線程調用wait] --> B[釋放對象鎖]B --> C[進入等待隊列]D[其他線程調用notify] --> E[喚醒等待線程]E --> F[線程嘗試重新獲取鎖]F --> G[獲取鎖后繼續執行]
Condition接口(java.util.concurrent.locks)
核心方法
Condition
接口提供了更靈活的線程協調機制,需配合Lock
使用:
await()
- 功能類似
wait()
,但支持更豐富的等待條件 - 可響應中斷:
awaitUninterruptibly()
- 支持超時:
await(long time, TimeUnit unit)
- 功能類似
signal()
- 喚醒單個等待線程(類似
notify()
) signalAll()
喚醒所有等待線程
- 喚醒單個等待線程(類似
使用示例
import java.util.concurrent.locks.*;class ConditionExample {private final Lock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();private int[] buffer = new int[10];private int count = 0;public void produce(int item) throws InterruptedException {lock.lock();try {while (count == buffer.length) notFull.await(); // 緩沖區滿時等待buffer[count++] = item;notEmpty.signal(); // 喚醒消費者} finally {lock.unlock();}}public int consume() throws InterruptedException {lock.lock();try {while (count == 0) notEmpty.await(); // 緩沖區空時等待int item = buffer[--count];notFull.signal(); // 喚醒生產者return item;} finally {lock.unlock();}}
}
對比分析
特性 | wait/notify | Condition |
---|---|---|
鎖機制 | 必須配合synchronized | 必須配合Lock實現 |
多條件等待 | 不支持 | 支持創建多個Condition實例 |
中斷響應 | 僅基礎中斷 | 提供awaitUninterruptibly() |
超時控制 | 有限支持 | 精確到納秒的超時控制 |
公平性 | 依賴synchronized | 可通過ReentrantLock配置 |
喚醒精確性 | notify隨機喚醒 | signal可定向喚醒特定條件隊列 |
最佳實踐
循環檢查條件
始終在循環中檢查等待條件,避免虛假喚醒:while (!condition) {obj.wait(); }
資源釋放
使用try-finally
確保鎖釋放:lock.lock(); try {// 臨界區代碼 } finally {lock.unlock(); }
選擇建議
- 簡單場景:優先使用
synchronized
+wait/notify
- 復雜同步:使用
Lock
+Condition
(如多條件隊列、公平鎖需求)
- 簡單場景:優先使用
注意:Java 5+推薦使用
java.util.concurrent
包中的高級同步工具(如BlockingQueue
),僅在底層控制需要時使用wait/notify或Condition。