首頁 > Java > java教程 > 為什麼一個執行緒在notify()或notifyAll()之後總是重新取得物件鎖?

為什麼一個執行緒在notify()或notifyAll()之後總是重新取得物件鎖?

Mary-Kate Olsen
發布: 2024-11-24 11:38:10
原創
443 人瀏覽過

Why Does One Thread Always Reacquire the Object Lock After notify() or notifyAll()?

notify()和notifyAll()之間的微妙區別

notify()和notifyAl l()之間的主要區別在於它們喚醒的等待執行緒數量(一個與所有),這提出了另一個問題:

為什麼總是有一個執行緒重新取得物件鎖定嗎?

一般情況下,notify()和notifyAll()都沒有指定選擇哪個等待執行緒來重新取得鎖定。 JVM 或系統執行緒調度程序會進行此選擇,該選擇可能是不確定的。

需要 notifyAll()

但是,在某些情況下使用notify()可能會導致死鎖,如下例所示:

生產者/消費者類notification()

public class ProducerConsumer {

    private final int MAX_SIZE = 1;  // Buffer size

    private List<Object> buf = new ArrayList<>();

    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 將一個物件放入緩衝區。
  2. 生產者 P2 P3 嘗試放入物件但被阻止,因為緩衝區已滿已滿。
  3. 消費者 C1 嘗試從緩衝區取得物件。
  4. C1 正在執行並取得對象,然後通知等待執行緒。
  5. P2 或 C2 可以是被通知喚醒,但它們在嘗試重新取得鎖定時都被阻止。
  6. C3 嘗試取得鎖定時也被阻止

因此,三個執行緒都無限期地等待,導致死鎖。

解決方案:notifyAll()

為了解決這個死鎖,必須在生產者/消費者程式碼中使用notifyAll()而不是notify()。這可以確保所有等待執行緒都被喚醒,防止死鎖。

建議:

對於大多數場景,notifyAll() 是首選方法,因為它可以避免潛在的死鎖。如果特定場景只需要喚醒一個特定的等待線程,那麼notify()可謹慎使用。

以上是為什麼一個執行緒在notify()或notifyAll()之後總是重新取得物件鎖?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板