1. 程式人生 > >多執行緒通訊的三大法器,你真的會用嗎?

多執行緒通訊的三大法器,你真的會用嗎?

wait, notify, notifyAll 是多執行緒之間通訊最重要的 3 個方法,今天,棧長給大家普及一下它們的知識要點及應用實戰。

定義

wait:讓持有該物件鎖的執行緒等待;

notify: 喚醒任何一個持有該物件鎖的執行緒;

notify: 喚醒所有持有該物件鎖的執行緒;

它們 3 個的關係是,呼叫物件的 wait 方法使執行緒暫停執行,通過 notify/ notifyAll 方法喚醒呼叫 wait 暫時的執行緒。

然而,它們並不是 Thread 類中的方法,而是 Object 類中的,為什麼呢!? 因為每個物件都有監視鎖,執行緒要操作某個物件當然是要獲取某個物件的鎖了,而不是執行緒的鎖。

如圖所示,wait 帶時間表示最大超時時間,過了時間還不喚醒就會自動喚醒執行緒重新競爭物件鎖。

幾個重要的點

1、呼叫物件的 wait, notify, notifyAll 方法需要擁有物件的監視器鎖,即它們只能在同步方法(塊)中使用;

2、呼叫 wait 方法會使用執行緒暫停並讓出 CPU 資源,同時釋放持有的物件的鎖;

3、多執行緒使用 notify 容易發生死鎖,一般使用 notifyAll;

4、關於 wait 和 sleep 的詳細區別請翻閱 《多執行緒 sleep 和 wait 的 5 個區別》這篇文章。

實戰

/**
 * 微信公眾號:Java技術棧
 */
public static void main(String[] args) {
    Object lock = new Object();
    Thread t1 = new Thread(() -> {
        synchronized (lock) {
            for (int i = 0; i < 20; i++) {
                System.out.print(i);
                if (i == 10) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    });

    Thread t2 = new Thread(() -> {
        synchronized (lock) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.print("Java技術棧");
            lock.notifyAll();
        }
    });

    t1.start();
    t2.start();
}

上面的例子結合 wait/ notifyAll 來演示了它們的相互作用。

執行緒 t1 首先輸出 012345678910,5秒後繼續輸出 Java技術棧111213141516171819


更多 Java 多執行緒技術文章請在Java技術棧微信公眾號後臺回覆關鍵字:多執行緒。

本文原創首發於微信公眾號:Java技術棧(id:javastack),關注公眾號在後臺回覆 "多執行緒" 可獲取更多,轉載請原樣保留本資訊。