首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 多線程核心:wait/notify 機制深度解析與實戰陷阱

     編輯:Java 綜合教學

Java 多線程核心:wait/notify 機制深度解析與實戰陷阱

wait()、notify()、notifyAll() 是 Object 類定義的基礎協作方法,構成了 Java 早期線程通信的基石。本文系統梳理其使用規則、執行流程、中斷處理、通知順序陷阱及條件判斷最佳實踐。

核心規則:必須在同步塊中調用

wait/notify 操作的是對象監視器(Monitor),調用前必須持有該對象的鎖,否則拋出 IllegalMonitorStateException。標準模式:

synchronized (lockObj) {
    // 檢查條件
    while (conditionNotMet) {
        lockObj.wait(); // 釋放鎖,進入等待隊列
    }
    // 執行業務邏輯
    lockObj.notifyAll(); // 喚醒等待線程
}

執行流程深度剖析

  1. 線程進入 synchronized 塊,獲取對象鎖。
  2. 調用 wait():釋放鎖,線程進入該對象的 等待集合,釋放 CPU。
  3. 另一線程獲取同一鎖,調用 notify/notifyAll():從等待集合移出一個/所有線程到 入口集合 競爭鎖。
  4. 關鍵點:notify 後不立即釋放鎖,需退出 synchronized 塊才釋放。喚醒的線程必須重新獲取鎖才能從 wait() 返回繼續執行。
// 錯誤示範:notify 後執行耗時操作導致喚醒線程無法及時獲取鎖
public void synNotifyMethod(Object lock) {
    synchronized (lock) {
        lock.notify();
        Thread.sleep(5000); // 持有鎖睡眠,喚醒線程被阻塞
    } // 此處才釋放鎖
}

五大實戰陷阱與解決方案

1. 中斷等待中的線程

調用 thread.interrupt() 可打斷 wait(),拋出 InterruptedException。注意區分:

  • Thread.interrupted():靜態方法,檢測當前線程中斷狀態並清除標誌。
  • thread.isInterrupted():實例方法,檢測指定線程中斷狀態,不清除標誌。

2. 通知順序錯誤導致信號丟失

若 notify() 先於 wait() 執行,等待線程將永久阻塞(除非被中斷)。解決:確保先 wait 後 notify,或使用 CountDownLatch/Semaphore 替代。

3. 條件判斷:為什麼用 while 而非 if?

經典場景:兩個消費者線程,一個生產者只生產一個元素。
if 判斷:第一個消費者消費後,第二個被喚醒直接執行刪除 → IndexOutOfBoundsException。
while 循環:被喚醒後重新檢查條件,發現隊列為空 → 繼續 wait(),避免越界。

// 正確模式
synchronized (lock) {
    while (list.isEmpty()) { // 循環檢查,防止虛假喚醒/條件變化
        lock.wait();
    }
    list.remove(0); // 安全執行
}

4. 虛假喚醒

線程可能在無 notify、無中斷的情況下自發醒來(JVM 允許),while 循環可有效防禦。

5. 使用 Lock + Condition 替代

JDK 1.5+ 推薦使用 ReentrantLock 配合 Condition,支持多條件隊列、可中斷等待、公平鎖等高級特性,語義更清晰。

最佳實踐檢查清單

  • [ ] 所有 wait/notify 在 synchronized(lockObj) 內調用
  • [ ] 條件判斷使用 while 循環
  • [ ] notifyAll() 優於 notify()(避免信號丟失)
  • [ ] notify 後盡快退出同步塊
  • [ ] 捕獲 InterruptedException 後保留中斷狀態或拋出
  • [ ] 新代碼優先考慮 BlockingQueue/Lock-Condition/CompletableFuture
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved