Java併發(二十一)----wait notify介紹

|舊市拾荒|發表於2023-12-25

1、小故事 - 為什麼需要 wait

  • 由於條件不滿足(沒煙幹不了活啊,等小M把煙送過來),小南不能繼續進行計算

  • 但小南如果一直佔用著鎖,其它人就得一直阻塞,效率太低

  • Java併發(二十一)----wait notify介紹

  • 於是老王單開了一間休息室(呼叫 wait 方法),讓小南到休息室(WaitSet)等著去了,但這時鎖釋放開,其它人可以由老王隨機安排進屋

  • 直到小M將煙送來,大叫一聲 [ 你的煙到了 ] (呼叫 notify 方法)

  • Java併發(二十一)----wait notify介紹

  • 小南於是可以離開休息室,重新進入競爭鎖的佇列

  • Java併發(二十一)----wait notify介紹

2、wait notify 原理

Java併發(二十一)----wait notify介紹

  • Owner 執行緒發現條件不滿足,呼叫 wait 方法,即可進入 WaitSet 變為 WAITING 狀態

  • BLOCKED 和 WAITING 的執行緒都處於阻塞狀態,不佔用 CPU 時間片

  • BLOCKED 執行緒會在 Owner 執行緒釋放鎖時喚醒

  • WAITING 執行緒會在 Owner 執行緒呼叫 notify 或 notifyAll 時喚醒,但喚醒後並不意味者立刻獲得鎖,仍需進入 EntryList 重新競爭

3、API 介紹

  • obj.wait() 讓進入 object 監視器的執行緒到 waitSet 等待

  • obj.notify() 在 object 上正在 waitSet 等待的執行緒中挑一個喚醒

  • obj.notifyAll() 讓 object 上正在 waitSet 等待的執行緒全部喚醒

它們都是執行緒之間進行協作的手段,都屬於 Object 物件的方法。必須獲得此物件的鎖,才能呼叫這幾個方法,否則會報IllegalMonitorStateException

final static Object obj = new Object();
​
public static void main(String[] args) {
​
    new Thread(() -> {
        synchronized (obj) {
            log.debug("執行....");
            try {
                obj.wait(); // 讓執行緒在obj上一直等待下去
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("其它程式碼....");
        }
    }).start();
​
    new Thread(() -> {
        synchronized (obj) {
            log.debug("執行....");
            try {
                obj.wait(); // 讓執行緒在obj上一直等待下去
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("其它程式碼....");
        }
    }).start();
​
    // 主執行緒兩秒後執行
    sleep(2);
    log.debug("喚醒 obj 上其它執行緒");
    synchronized (obj) {
        obj.notify(); // 喚醒obj上隨機一個執行緒
        // obj.notifyAll(); // 喚醒obj上所有等待執行緒
    }
}

notify 的一種結果

20:00:53.096 [Thread-0] c.TestWaitNotify - 執行....
20:00:53.099 [Thread-1] c.TestWaitNotify - 執行....
20:00:55.096 [main] c.TestWaitNotify - 喚醒 obj 上其它執行緒
20:00:55.096 [Thread-0] c.TestWaitNotify - 其它程式碼....

notifyAll 的結果

19:58:15.457 [Thread-0] c.TestWaitNotify - 執行....
19:58:15.460 [Thread-1] c.TestWaitNotify - 執行....
19:58:17.456 [main] c.TestWaitNotify - 喚醒 obj 上其它執行緒
19:58:17.456 [Thread-1] c.TestWaitNotify - 其它程式碼....
19:58:17.456 [Thread-0] c.TestWaitNotify - 其它程式碼....

wait() 方法會釋放物件的鎖,進入 WaitSet 等待區,從而讓其他執行緒就機會獲取物件的鎖。無限制等待,直到 notify 為止

wait(long n) 有時限的等待, 到 n 毫秒後結束等待,或是被 notify

 

相關文章