| 維度 | sleep() | wait() |
|---|---|---|
| 所屬類 | Thread (static) | Object |
| 鎖行為 | 不釋放鎖 | 釋放鎖 |
| 喚醒方式 | 時間到期自動喚醒 | notify()/notifyAll() 或超時 |
| 調用前提 | 無 | 必須在 synchronized 塊/方法中 |
| 異常處理 | InterruptedException | InterruptedException + IllegalMonitorStateException(非同步塊調用) |
class ThreadSleep implements Runnable {
int count = 0;
public void run() { count(); }
public void count() {
while (count < 20) {
synchronized (this) { // 加鎖
System.out.println(Thread.currentThread().getName() + " count=" + count);
count++;
try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); }
}
}
}
}
// 輸出:線程甲獨佔執行 0~19,線程乙全程等待鎖釋放
現象:sleep(100) 期間鎖未釋放,另一線程無法進入同步塊,導致併發度為 0。
public void count() {
while (count < 20) {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + " count=" + count);
count++;
try { this.wait(100); } catch (Exception e) { e.printStackTrace(); }
}
}
}
// 輸出:線程甲、乙交替執行,鎖在 wait 期間被釋放
關鍵點:wait(100) 相當於 wait() + 超時自動喚醒,且釋放鎖,其他線程可獲取鎖繼續執行。
class SharedBuffer {
private final List<Integer> buffer = new ArrayList<>();
private final int capacity = 5;
public synchronized void produce(int value) throws InterruptedException {
while (buffer.size() == capacity) wait(); // 滿了等待
buffer.add(value);
notifyAll(); // 喚醒消費者
}
public synchronized int consume() throws InterruptedException {
while (buffer.isEmpty()) wait(); // 空了等待
int value = buffer.remove(0);
notifyAll(); // 喚醒生產者
return value;
}
}
wait():防止虛假喚醒(spurious wakeup)。
while (conditionNotMet) wait(); // 而非 if
notifyAll():除非確定只有一類線程等待,否則 notify() 可能喚醒錯誤線程導致活鎖。Thread.currentThread().interrupt() 或拋出。sleep() 是「暫停當前線程,鎖不放」;wait() 是「進入等待集,鎖釋放,等通知」。理解鎖所有權轉移是掌握兩者本質區別的鑰匙。實際開發中,併發包(java.util.concurrent)提供的 Condition、BlockingQueue、CountDownLatch 等高級工具往往比裸露的 wait/notify 更安全、更易維護——能用高級 API 就別手寫底層協作。