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

Java 多執行緒 notify 與 notifyAll 核心差異:喚醒策略與死鎖風險深度解析

     編輯:Java 程式設計入門

核心結論先行

notify():隨機喚醒單一在該物件監視器上 wait() 的執行緒。
notifyAll():喚醒所有在該物件監視器上 wait() 的執行緒。
關鍵點:被喚醒的執行緒不會立即執行,必須重新競爭鎖(monitor),只有拿到鎖的執行緒才能從 wait() 返回繼續執行。

為什麼 notify() 容易導致死鎖?

經典「生產者-消費者」缓衝區模型示範:

public synchronized void put(Object o) {
    while (buf.size() == MAX_SIZE) wait();  // 滿了等待
    buf.add(o);
    notify();  // 唤醒一个等待者
}

public synchronized Object get() {
    while (buf.size() == 0) wait();         // 空了等待
    Object o = buf.remove(0);
    notify();  // 唤醒一个等待者
    return o;
}

死鎖演進場景

  1. 緩衝區滿,生產者 P1 執行 wait() 釋放鎖並進入等待集
  2. 消費者 C1 執行 get(),移除一個元素,呼叫 notify()
  3. notify() 隨機喚醒另一個消費者 C2(而非生產者 P1)
  4. C2 獲取鎖後發現緩衝區仍非空,正常消費並再次 notify()
  5. 此時生產者 P1 仍在等待集中永不被喚醒,系統僅剩消費者活躍,生產線程全部飢餓

若改用 notifyAll(),P1 會被喚醒並有機會競爭鎖,系統恢復平衡。

最佳實踐:永遠優先使用 notifyAll()

  • 除非你能嚴格證明:等待集中所有執行緒的等待條件完全等價,且喚醒任意一個都能正確推進系統狀態
  • 實務上極難滿足上述條件,notifyAll() 的效能開銷微乎其微(現代 JVM 優化極好)
  • Java 5+ 建議直接使用 java.util.concurrent 高階組件(Condition、BlockingQueue、Semaphore),完全避開 wait/notify 陷阱

Condition 替代方案:精確控制喚醒對象

Lock lock = new ReentrantLock();
Condition notFull  = lock.newCondition(); // 生產者等待
Condition notEmpty = lock.newCondition(); // 消費者等待

public void put(Object o) {
    lock.lock();
    try {
        while (buf.size() == MAX_SIZE) notFull.await();
        buf.add(o);
        notEmpty.signal(); // 精確喚醒消費者
    } finally { lock.unlock(); }
}

public Object get() {
    lock.lock();
    try {
        while (buf.isEmpty()) notEmpty.await();
        Object o = buf.remove(0);
        notFull.signal();  // 精確喚醒生產者
        return o;
    } finally { lock.unlock(); }
}

Condition 將單一物件的等待集拆分為多個邏輯等待隊列,實現「該喚醒誰、喚醒誰」,徹底解決 notify() 的盲目喚醒問題。

延伸閱讀

  • StackOverflow 經典討論:notify vs notifyAll all over again
  • 《Java 併發編程實戰》第 14 章:顯式條件佇列
  • JDK 源碼:ObjectMonitor::notify() vs ObjectMonitor::notifyAll() 實作差異

一句話總結

除非你是 JVM 核心庫開發者,否則請忘掉 notify(),永遠使用 notifyAll() 或更高階的 Condition/BlockingQueue。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved