1. 程式人生 > >多執行緒---java中鎖池和等待池的概念

多執行緒---java中鎖池和等待池的概念

鎖池和等待池

在java中,每個物件都有兩個池,鎖(monitor)池和等待池

  • 鎖池:假設執行緒A已經擁有了某個物件(注意:不是類)的鎖,而其它的執行緒想要呼叫這個物件的某個synchronized方法(或者synchronized塊),由於這些執行緒在進入物件的synchronized方法之前必須先獲得該物件的鎖的擁有權,但是該物件的鎖目前正被執行緒A擁有,所以這些執行緒就進入了該物件的鎖池中。
  • 等待池:假設一個執行緒A呼叫了某個物件的wait()方法,執行緒A就會釋放該物件的鎖後,進入到了該物件的等待池中

 物件鎖和類鎖的概念在我這篇部落格有提到,不知道的同學可以點這個連結瞭解一下

https://blog.csdn.net/weixin_42504145/article/details/84995202  靜態方法加鎖和非靜態方法加鎖的區別

深入理解: 

然後再來說notify和notifyAll的區別

  • 如果執行緒呼叫了物件的 wait()方法,那麼執行緒便會處於該物件的等待池中,等待池中的執行緒不會去競爭該物件的鎖
  • 當有執行緒呼叫了物件的 notifyAll()方法(喚醒所有 wait 執行緒)或 notify()方法(只隨機喚醒一個 wait 執行緒),被喚醒的的執行緒便會進入該物件的鎖池中,鎖池中的執行緒會去競爭該物件鎖。也就是說,呼叫了notify後只要一個執行緒會由等待池進入鎖池,而notifyAll會將該物件等待池內的所有執行緒移動到鎖池中,等待鎖競爭
  • 優先順序高的執行緒競爭到物件鎖的概率大,假若某執行緒沒有競爭到該物件鎖,它還會留在鎖池中,唯有執行緒再次呼叫 wait()方法,它才會重新回到等待池中。而競爭到物件鎖的執行緒則繼續往下執行,直到執行完了 synchronized 程式碼塊,它會釋放掉該物件鎖,這時鎖池中的執行緒會繼續競爭該物件鎖。

wait() ,notifyAll(),notify() 三個方法都是Object類中的方法. 

關於wait() ,notifyAll(),notify() 三個方法的理解

wait() 
public final void wait() throws InterruptedException,IllegalMonitorStateException
該方法用來將當前執行緒置入休眠狀態,直到接到通知或被中斷為止。在呼叫 wait()之前,執行緒必須要獲得該物件的物件級別鎖,即只能在同步方法或同步塊中呼叫 wait()方法。進入 wait()方法後,當前執行緒釋放鎖。在從 wait()返回前,執行緒與其他執行緒競爭重新獲得鎖。如果呼叫 wait()時,沒有持有適當的鎖,則丟擲 IllegalMonitorStateException,它是 RuntimeException 的一個子類,因此,不需要 try-catch 結構。

notify() 
public final native void notify() throws IllegalMonitorStateException
該方法也要在同步方法或同步塊中呼叫,即在呼叫前,執行緒也必須要獲得該物件的物件級別鎖,的如果呼叫 notify()時沒有持有適當的鎖,也會丟擲 IllegalMonitorStateException。

該方法用來通知那些可能等待該物件的物件鎖的其他執行緒。如果有多個執行緒等待,則執行緒規劃器任意挑選出其中一個 wait()狀態的執行緒來發出通知,並使它等待獲取該物件的物件鎖(notify 後,當前執行緒不會馬上釋放該物件鎖,wait 所在的執行緒並不能馬上獲取該物件鎖,要等到程式退出 synchronized 程式碼塊後,當前執行緒才會釋放鎖,wait所在的執行緒也才可以獲取該物件鎖),但不驚動其他同樣在等待被該物件notify的執行緒們。當第一個獲得了該物件鎖的 wait 執行緒執行完畢以後,它會釋放掉該物件鎖,此時如果該物件沒有再次使用 notify 語句,則即便該物件已經空閒,其他 wait 狀態等待的執行緒由於沒有得到該物件的通知,會繼續阻塞在 wait 狀態,直到這個物件發出一個 notify 或 notifyAll。這裡需要注意:它們等待的是被 notify 或 notifyAll,而不是鎖。這與下面的 notifyAll()方法執行後的情況不同。

notifyAll() 
public final native void notifyAll() throws IllegalMonitorStateException
該方法與 notify ()方法的工作方式相同,重要的一點差異是:

notifyAll 使所有原來在該物件上 wait 的執行緒統統退出 wait 的狀態(即全部被喚醒,不再等待 notify 或 notifyAll,但由於此時還沒有獲取到該物件鎖,因此還不能繼續往下執行),變成等待獲取該物件上的鎖,一旦該物件鎖被釋放(notifyAll 執行緒退出呼叫了 notifyAll 的 synchronized 程式碼塊的時候),他們就會去競爭。如果其中一個執行緒獲得了該物件鎖,它就會繼續往下執行,在它退出 synchronized 程式碼塊,釋放鎖後,其他的已經被喚醒的執行緒將會繼續競爭獲取該鎖,一直進行下去,直到所有被喚醒的執行緒都執行完畢。
 

示例:

關於sleep()和wait(),以下描述錯誤的一項是: 
- A sleep是執行緒類(Thread)的方法,wait是Object類的方法; 
- B sleep不釋放物件鎖,wait放棄物件鎖 
- C sleep暫停執行緒、但監控狀態仍然保持,結束後會自動恢復 
- D wait後進入等待鎖定池,只有針對此物件發出notify方法後獲得物件鎖進入執行狀態
答案是*,具體原因可以參考這篇部落格  https://blog.csdn.net/chengonghao/article/details/52160741

Java中notify 和 notifyAll有什麼區別?

這個上邊已經提到,這裡不再闡述了。