多線程通訊的三大法器,你真的會用嗎?

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

定義

wait:讓持有該對象鎖的線程等待;多線程

notify: 喚醒任何一個持有該對象鎖的線程;線程

notify: 喚醒全部持有該對象鎖的線程;code

它們 3 個的關係是,調用對象的 wait 方法使線程暫停運行,經過 notify/ notifyAll 方法喚醒調用 wait 暫時的線程。對象

然而,它們並非 Thread 類中的方法,而是 Object 類中的,爲何呢!? 由於每一個對象都有監視鎖,線程要操做某個對象固然是要獲取某個對象的鎖了,而不是線程的鎖。blog

如圖所示,wait 帶時間表示最大超時時間,過了時間還不喚醒就會自動喚醒線程從新競爭對象鎖。資源

幾個重要的點

一、調用對象的 wait, notify, notifyAll 方法須要擁有對象的監視器鎖,即它們只能在同步方法(塊)中使用;get

二、調用 wait 方法會使用線程暫停並讓出 CPU 資源,同時釋放持有的對象的鎖;同步

三、多線程使用 notify 容易發生死鎖,通常使用 notifyAll;it

四、關於 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),關注公衆號在後臺回覆 "多線程" 可獲取更多,轉載請原樣保留本信息。

相關文章
相關標籤/搜索