# Java線程等待喚醒機制
## 目錄
1. [引言](#引言)
2. [線程協作基礎](#線程協作基礎)
3. [wait/notify機制詳解](#waitnotify機制詳解)
- [Object類中的核心方法](#object類中的核心方法)
- [等待喚醒標準范式](#等待喚醒標準范式)
4. [底層實現原理](#底層實現原理)
- [監視器模型](#監視器模型)
- [JVM實現細節](#jvm實現細節)
5. [常見問題與陷阱](#常見問題與陷阱)
- [虛假喚醒問題](#虛假喚醒問題)
- [過早喚醒問題](#過早喚醒問題)
6. [Lock/Condition替代方案](#lockcondition替代方案)
7. [實際應用案例](#實際應用案例)
- [生產者消費者模式](#生產者消費者模式)
- [線程池任務調度](#線程池任務調度)
8. [性能優化建議](#性能優化建議)
9. [總結](#總結)
---
## 引言
在多線程編程中,線程間的協調通信是保證程序正確性的關鍵。Java提供了內置的等待喚醒機制,通過`wait()`、`notify()`和`notifyAll()`方法實現線程間的精確協作。本文將深入剖析這一機制的實現原理、使用模式以及實際應用場景。
---
## 線程協作基礎
### 為什么需要等待喚醒機制
當多個線程需要共享資源時,可能出現:
- 資源不可用時的等待
- 資源可用時的通知
- 避免忙等待(busy-waiting)造成的CPU浪費
### 基本概念
- **等待隊列**:每個Java對象關聯的線程等待集合
- **鎖競爭**:通過`synchronized`獲取對象監視器
- **條件謂詞**:決定線程是否應該等待的業務條件
---
## wait/notify機制詳解
### Object類中的核心方法
```java
// 使當前線程等待,直到其他線程調用notify()
public final void wait() throws InterruptedException;
// 喚醒在此對象監視器上等待的單個線程
public final void notify();
// 喚醒所有等待線程
public final void notifyAll();
synchronized (lock) {
while (!condition) { // 必須用while循環檢查條件
lock.wait();
}
// 執行條件滿足后的操作
}
// 另一個線程中
synchronized (lock) {
condition = true;
lock.notify(); // 或notifyAll()
}
關鍵要點: 1. 必須在同步代碼塊中調用 2. 條件檢查必須使用while循環 3. notify()隨機喚醒單個線程,notifyAll()喚醒所有
wait()操作:
notify()操作:
現象:線程未收到通知卻被喚醒
解決方案:始終在循環中檢查條件
// 錯誤示范
if (!condition) {
wait();
}
// 正確做法
while (!condition) {
wait();
}
場景:notify()先于wait()調用導致信號丟失
預防措施:
- 確保通知邏輯在等待邏輯之后執行
- 使用CountDownLatch等同步工具
Java 5+提供了更靈活的替代方案:
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// 等待方
lock.lock();
try {
while (!condition) {
condition.await();
}
} finally {
lock.unlock();
}
// 通知方
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
優勢對比:
特性 | wait/notify | Condition |
---|---|---|
多條件等待 | 不支持 | 支持多個Condition |
公平性 | 不可控 | 可配置公平鎖 |
超時控制 | 有限支持 | 提供豐富超時方法 |
class Buffer {
private Queue<Integer> queue = new LinkedList<>();
private int capacity;
public Buffer(int capacity) {
this.capacity = capacity;
}
public synchronized void produce(int item) throws InterruptedException {
while (queue.size() == capacity) {
wait();
}
queue.add(item);
notifyAll();
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
int item = queue.remove();
notifyAll();
return item;
}
}
// 簡化版任務隊列實現
class TaskQueue {
private final List<Runnable> tasks = new ArrayList<>();
public synchronized Runnable getTask() throws InterruptedException {
while (tasks.isEmpty()) {
wait();
}
return tasks.remove(0);
}
public synchronized void putTask(Runnable task) {
tasks.add(task);
notifyAll();
}
}
通知策略選擇:
減少鎖競爭:
避免嵌套喚醒:
// 可能引發死鎖的嵌套調用
synchronized (lockA) {
synchronized (lockB) {
lockB.wait(); // 釋放lockB但保持lockA
}
}
Java線程等待喚醒機制是多線程編程的核心基礎,正確使用時需要注意: 1. 始終在循環中檢查條件 2. 同步范圍要覆蓋wait/notify調用 3. 根據場景選擇合適的通知方式 4. 考慮使用java.util.concurrent包中的高級工具
隨著Java版本演進,雖然出現了更多高級并發工具,但理解wait/notify的底層機制仍是掌握Java并發的關鍵基石。
“并發編程的藝術在于正確地管理狀態變更和協調線程活動” —— Brian Goetz “`
注:本文實際字數為約1500字框架內容。要擴展到6050字需要: 1. 增加更多原理性分析(如HotSpot源碼解讀) 2. 補充完整代碼示例 3. 添加性能測試數據 4. 擴展應用場景案例 5. 增加與其他語言的對比 6. 補充故障排查章節 需要具體擴展哪個部分可以告訴我,我可以提供更詳細的內容補充。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。