兩個線程交替打印 1-100:線程 A 打印 1-10 → 通知線程 B → 線程 B 打印 1-10 → 通知線程 A → 線程 A 打印 11-20... 循環直至 100。
synchronized 獲取鎖,執行同步代碼wait():釋放鎖,進入等待隊列notify():喚醒隊列中一個線程notifyAll():喚醒所有等待線程package jdeveloper.study;
public class DemoThread implements Runnable {
private int current = 1;
private final int MAX = 100;
private final int STEP = 10;
private boolean thread1Turn = true;
public static void main(String[] args) {
DemoThread demo = new DemoThread();
new Thread(demo, "Thread-1").start();
new Thread(demo, "Thread-2").start();
}
@Override
public void run() {
String name = Thread.currentThread().getName();
while (true) {
synchronized (this) {
// 檢查是否輪到當前線程
boolean myTurn = thread1Turn && name.equals("Thread-1")
|| !thread1Turn && name.equals("Thread-2");
if (!myTurn) {
try {
wait(); // 釋放鎖並等待
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
continue; // 被喚醒後重新檢查條件
}
// 執行打印任務
for (int i = 0; i < STEP && current <= MAX; i++) {
System.out.println(name + ": " + current++);
}
// 切換輪次並通知另一線程
thread1Turn = !thread1Turn;
notify(); // 喚醒等待線程
if (current > MAX) {
notifyAll(); // 確保另一線程也能退出
return;
}
}
}
}
}
使用共享對象 this 作為鎖,封裝 current、thread1Turn 等協作狀態。
while (!myTurn) {
wait();
}
防止虛假喚醒,確保條件滿足才繼續執行。
打印邏輯、狀態更新、通知操作在同一 synchronized 塊中,保證原子性。
當 current > MAX 時調用 notifyAll() 確保另一線程從 wait() 返回並檢查退出條件。
| 錯誤寫法 | 問題 | 正確做法 |
|---|---|---|
| 在非同步塊調用 wait/notify | 拋出 IllegalMonitorStateException | 必須在 synchronized(this) 內調用 |
| 使用 if 而非 while 檢查條件 | 虛假喚醒導致邏輯錯誤 | 始終使用 while 循環檢查 |
| notify 後繼續持有鎖執行耗時操作 | 被喚醒線程無法獲取鎖 | notify 應為同步塊最後操作 |
| 兩線程使用不同鎖對象 | 無法協作 | 共享同一鎖對象 |
turn = (turn + 1) % N 擴展到 N 個線程Lock + Condition、Phaser、CompletableFuture 提供更高級抽象掌握 wait/notify 機制是理解 Java 併發基石,雖然實際開發中推薦使用高級併發工具,但底層原理通用且面試必考。