“嗨,阿米戈!”

“嗨,里希!”

“我將向您介紹 Object 類的waitnotifynotifyAll方法。”

“今天我們只是熟悉一下它們,但我們稍後會回來,花更多時間在這上面。”

“好的。”

“這些方法是作為線程同步機制的一部分而發明的。”

“讓我提醒你,Java 有一個內置的機制來控制不同線程對共享資源(對象)的訪問。一個線程可以聲明一個對象處於忙碌狀態,其他線程將不得不等待,直到這個忙碌的對像被釋放。 “

“我記得。你用同步關鍵字來做到這一點。”

“對。通常,代碼看起來像這樣:”

public void print()
{
 Object monitor = getMonitor();
 synchronized(monitor)
 {
  System.out.println("text");
 }
}

“還記得它是如何工作的嗎?”

“是的。如果兩個線程同時調用 print() 方法,其中一個線程將進入標記為 synchronized 的塊並鎖定監視器,這使得第二個線程將等待直到監視器被釋放。”

“對。一旦一個線程進入標記為synchronized的塊,monitor對象就被標記為busy,其他線程將被迫等待monitor對像被釋放。同一個monitor對象可以在程序的各個部分使用。 “

“對了,你為什麼選擇班長這個名字?”

“監視器就是您通常所說的存儲忙碌或空閒狀態的對象。”

“這就是等待通知方法發揮作用的地方。”

“其實,真的就只有這兩種方法,其他的都是這些方法的改編而已。”

“現在讓我們來了解一下wait 方法是什麼以及我們為什麼需要它。

“有時在程序中會出現這樣的情況,線程進入同步代碼塊並鎖定監視器,但由於缺少某些數據而無法繼續執行。例如,它需要處理的文件尚未完成下載或像那樣的東西。”

“我們可以等待文件下載。您可以使用循環檢查它。如果文件尚未下載,則休眠一秒鐘左右,然後再次檢查,直到下載完成。”

“像這樣的東西:”

while(!file.isDownloaded())
{
 Thread.sleep(1000);
}
processFile(file);

“但在我們的例子中,這種等待的代價太大了。由於我們的線程鎖定了監視器,其他線程也被迫等待,即使它們可能已經擁有所需的數據。”

“發明了wait()方法來解決這個問題。這個方法導致線程釋放監視器,然後 «suspends» 線程。

“您只能在監視器繁忙時調用監視器對象的 wait 方法,即只能在同步塊內。發生這種情況時,線程會暫時停止運行,並釋放監視器,以便其他線程可以使用它。”

“通常情況下,線程會進入同步塊並調用等待,從而釋放監視器。”

“然後第二個線程將進入並暫停,然後是第三個,依此類推。”

“線程如何恢復?”

“為此,還有第二種方法:通知。”

“您只能在監視器繁忙時調用監視器對象的notify / notifyAll方法,即只能在同步塊內調用。notifyAll方法喚醒所有等待此監視器對象的線程。”

notify方法‘解凍’了一個隨機線程,但notifyAll方法解凍了該監視器的所有 «frozen» 線程。”

“非常有趣。謝謝你,Rishi。”

“還有對 wait() 方法的改編:”

等待() 方法 解釋
void wait(long timeout)
線程“凍結”,但在等待作為參數傳遞給方法的毫秒數後,它會自動“解凍”。
void wait(long timeout, int nanos)
線程“凍結”,但在等待作為參數傳遞給方法的納秒數後,它會自動“解凍”。

“我們也將其稱為超時等待。該方法的工作方式與普通等待一樣,但如果指定的時間已經過去並且線程尚未被喚醒,它會自行喚醒。”