| 方法 | 所屬類別 | 行為 |
|---|---|---|
| wait() | Object | 釋放鎖、進入等待集合,直到 notify/notifyAll 或超時 |
| notify() | Object | 喚醒單一等待執行緒 |
| notifyAll() | Object | 喚醒所有等待執行緒 |
| sleep() | Thread | **不釋放鎖**,單純暫停 |
| yield() | Thread | **不釋放鎖**,讓出 CPU |
必須在 synchronized 方法/區塊內呼叫,否則拋出 IllegalMonitorStateException。
public class Game implements Runnable {
private final Set<Athlete> players = new HashSet<>();
private boolean start = false;
public synchronized void prepare(Athlete a) throws InterruptedException {
System.out.println(a + " ready!");
while (!start) wait(); // 釋放鎖等待
System.out.println(a + " go!");
}
public synchronized void go() {
start = true;
notifyAll(); // 喚醒所有選手
}
public void ready() {
for (Athlete a : players) new Thread(a).start();
}
@Override public void run() {
System.out.println("Ready......");
ready();
System.out.println("Go!");
go();
}
public static void main(String[] args) {
Game game = new Game();
for (int i = 0; i < 10; i++) game.addPlayer(new Athlete(i, game));
new Thread(game).start();
}
}
class Athlete implements Runnable {
private final int id;
private final Game game;
public Athlete(int id, Game game) { this.id = id; this.game = game; }
@Override public void run() {
try { game.prepare(this); }
catch (InterruptedException e) { System.out.println(this + " quit"); }
}
@Override public String toString() { return "Athlete<" + id + ">"; }
}
輸出:所有選手先印 "ready!",主執行緒印 "Go!" 後,選手依序印 "go!"。
class Monitor implements Runnable {
private volatile boolean go = false;
public void gotMessage() { go = true; }
public void watching() { while (!go); } // 空迴圈燒 CPU
@Override public void run() { watching(); System.out.println("He has gone."); }
}
class Monitor implements Runnable {
private volatile boolean go = false;
public synchronized void gotMessage() { go = true; notify(); }
public synchronized void watching() throws InterruptedException {
while (!go) wait(); // 釋放鎖、進入等待態
}
@Override public void run() {
try { watching(); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("He has gone.");
}
}
synchronized (lock) {
while (conditionNotMet) {
lock.wait(); // 1. 釋放鎖 2. 等待 3. 重新獲得鎖
}
// 條件滿足,執行關鍵區
}
volatile 修飾條件旗標,保證可見性。| 類別 | 優勢 | |
|---|---|---|
java.util.concurrent.locks.Condition | 單一鎖支援多條件隊列,API 更豐富 (await(), signal()) | |
BlockingQueue | 生產者-消費者模式首選,內建阻塞 | |
CountDownLatch / CyclicBarrier / Phaser | 特定同步場景專用 | |
CompletableFuture / parallelStream | 非阻塞組合式非同步 |
| 錯誤 | 後果 | 修正 |
|---|---|---|
| 非 synchronized 中呼叫 wait/notify | IllegalMonitorStateException | 加上 synchronized 區塊 |
| 用 if 替代 while 檢查條件 | 虛假喚醒導致邏輯錯誤 | 改用 while (condition) wait() |
| notify() 單一喚醒但有多種條件 | 喚醒錯誤執行緒,造成活鎖 | 改用 notifyAll() 或 Condition |
| 鎖物件不一致 | wait/notify 無效 | 確保同一物件實例 |
wait/notify 是 Java 線程協作的基石,理解「釋放鎖→等待→重獲鎖」狀態機與「while 迴圈防虛假喚醒」模式至關重要。現代開發優先使用 java.util.concurrent 高層抽象,但掌握底層機制有助於除錯與理解框架原理。