多執行緒通訊的三大法器,你真的會用嗎?
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),關注公眾號在後臺回覆 "多執行緒" 可獲取更多,轉載請原樣保留本資訊。