更新時間:2020-11-25 17:54:54 來源:動力節點 瀏覽1866次
在java中,每個對象都有兩個池,鎖池和等待池。Java平臺中,因為有內置鎖的機制,每個對象都可以承擔鎖的功能。Java虛擬機會為每個對象維護兩個“隊列”(姑且稱之為“隊列”,盡管它不一定符合數據結構上隊列的“先進先出”原則):一個叫Entry Set(入口集),另外一個叫Wait Set(等待集)。對于任意的對objectX,objectX的Entry Set用于存儲等待獲取objectX這個鎖的所有線程,也就是傳說中的鎖池,objectX的Wait Set用于存儲執行了objectX.wait()/wait(long)的線程,也就是等待池。
下面我們來看鎖池和等待池的具體介紹:
鎖池:假設線程A已經擁有了某個對象(注意:不是類)的鎖,而其它的線程想要調用這個對象的某個synchronized方法(或者synchronized塊),由于這些線程在進入對象的synchronized方法之前必須先獲得該對象的鎖的擁有權,但是該對象的鎖目前正被線程A擁有,所以這些線程就進入了該對象的鎖池中。
等待池:假設一個線程A調用了某個對象的wait()方法,線程A就會釋放該對象的鎖(因為wait()方法必須出現在synchronized中,這樣自然在執行wait()方法之前線程A就已經擁有了該對象的鎖),同時線程A就進入到了該對象的等待池中。如果另外的一個線程調用了相同對象的notifyAll()方法,那么處于該對象的等待池中的線程就會全部進入該對象的鎖池中,準備爭奪鎖的擁有權。如果另外的一個線程調用了相同對象的notify()方法,那么僅僅有一個處于該對象的等待池中的線程(隨機)會進入該對象的鎖池。
設objectX是任意一個對象,假設有線程A、B、C同時申請objectX這個對象鎖,那么由于任意一個時刻只有一個線程能夠獲得(占用/持有)這個鎖,因此除了勝出(即獲得了鎖)的線程(這里假設是B)外,其他線程(這里就是A和C)都會被暫停(線程的生命周期狀態會被調整為BLOCKED)。這些因申請鎖而落選的線程就會被存入objectX對應的鎖池之中。當objectX被其持有線程(這里就是B)釋放時,鎖池中的一個任意(注意是“任意”,而不一定是鎖池中等待時間最長或者最短的)線程會被喚醒(即線程的生命周期狀態變更為RUNNABLE)。這個被喚醒的線程會與其他活躍線程(即不處于鎖池之中,且線程的生命周期狀態為RUNNABLE的線程)再次搶占objectX。這時,被喚醒的線程如果成功申請到objectX,那么該線程就從鎖池中移除。否則,被喚醒的線程仍然會停留在鎖池中,并再次被暫停,以等待下次申請鎖的機會。
如果有個線程執行了objectX.wait(),那么該線程就會被暫停(線程的生命周期狀態會被調整為Waiting),并且會釋放掉objectX鎖,然后被存入objectX的等待池之中。此時,該線程就被稱為objectX的等待線程。當其他線程執行了objectX.notify()/notifyAll()時,等待池中的一個(或者多個,取決于被調用的是notify還是notifyAll方法)任意(注意是“任意”,而不一定是等待池中等待時間最長或者最短的)等待線程會被喚醒,這些被喚醒的線程會被放到鎖池中,會與鎖池中已經存在的線程以及其他(可能的)活躍線程共同參與搶奪objectX。至于代碼中到底是使用notify還是notifyAll方法,這個要根據實際情況來分析。
實際上Java鎖池和等待池的概念在Java中并不多見,因此,Java鎖池和等待池的相關知識也容易被人忽視。不過,慶幸的是,在本站的Java多線程教程中有詳細的講解,想要拓展知識的小伙伴趕緊抓住機會前去學習吧!
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習