日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java设置等待锁的时间_java的锁池和等待池

發布時間:2025/3/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java设置等待锁的时间_java的锁池和等待池 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

謝邀。不知道題中的一段文字出自何處。“鎖池”和“等待池”這種翻譯我還是頭一回見。不過,題主的思路已經對了,即不拘泥于文字,而是在考慮這兩個東西在鎖的調度(即決定哪個線程可以獲得鎖的過程)中起到什么作用。

Java平臺中,每個對象都有一個唯一與之對應的內部鎖(Monitor)。Java虛擬機會為每個對象維護兩個“隊列”(姑且稱之為“隊列”,盡管它不一定符合數據結構上隊列的“先進先出”原則):一個叫Entry Set(入口集),另外一個叫Wait Set(等待集)。對于任意的對象objectX,objectX的Entry Set用于存儲等待獲取objectX對應的內部鎖的所有線程。objectX的Wait Set用于存儲執行了objectX.wait()/wait(long)的線程。

設objectX是任意一個對象,monitorX是這個對象對應的內部鎖,假設有線程A、B、C同時申請monitorX,那么由于任意一個時刻只有一個線程能夠獲得(占用/持有)這個鎖,因此除了勝出(即獲得了鎖)的線程(這里假設是B)外,其他線程(這里就是A和C)都會被暫停(線程的生命周期狀態會被調整為BLOCKED)。這些因申請鎖而落選的線程就會被存入objectX對應的Entry Set(以下記為entrySetX)之中。當monitorX被其持有線程(這里就是B)釋放時,entrySetX中的一個任意(注意是“任意”,而不一定是Entry Set中等待時間最長或者最短的)線程會被喚醒(即線程的生命周期狀態變更為RUNNABLE)。這個被喚醒的線程會與其他活躍線程(即不處于Entry Set之中,且線程的生命周期狀態為RUNNABLE的線程)再次搶占monitorX。這時,被喚醒的線程如果成功申請到monitorX,那么該線程就從entrySetX中移除。否則,被喚醒的線程仍然會停留在entrySetX,并再次被暫停,以等待下次申請鎖的機會。

如果有個線程執行了objectX.wait(),那么該線程就會被暫停(線程的生命周期狀態會被調整為WAITTING)并被存入objectX的Wait Set(以下記為waitSetX)之中。此時,該線程就被稱為objectX的等待線程。當其他線程執行了objectX.notify()/notifyAll()時,waitSetX中的一個(或者多個,取決于被調用的是notify還是notifyAll方法)任意(注意是“任意”,而不一定是Entry Set中等待時間最長或者最短的)等待線程會被喚醒(線程的生命周期狀態變更為RUNNABLE)。這些被喚醒的線程會與entrySetX中被喚醒的線程以及其他(可能的)活躍線程共同參與搶奪monitorX。如果其中一個被喚醒的等待線程成功申請到鎖,那么該線程就會從waitSetX中移除。否則,這些被喚醒的線程仍然停留在waitSetX中,并再次被暫停,以等待下次申請鎖的機會。

@劉方外

我理解調用對象的 notifyAll方法后,waitSet 上的線程都會加入到 entrySet 中的吧?在一個持有鎖的線程釋放鎖后,應該只有 entrySet 隊列的線程可能獲取鎖,那這個通知是 park 來實現的嗎?是否有保證獲取鎖公平性的相關設置?

1、從Java虛擬機性能的角度來說,Java虛擬機沒有必要在notifyAll調用之后“將Wait Set中的線程移入Entry Set”。首先,從一個“隊列”移動到另外一個“隊列”是有開銷的,其次,雖然notifyAll調用后Wait Set中的多個線程會被喚醒,但是這些被喚醒的線程極端情況下可能沒有任何一個能夠獲得鎖(比如被其他活躍線程搶先下手了)或者即便可以獲得鎖也可能不能繼續運行(比如這些等待線程所需的等待條件又再次不成立)。那么這個時候,這些等待線程仍然需要老老實實在wait set中待著。因此,如果notifyAll調用之后就將等待線程移出wait set會導致浪費(白白地進出“隊列”)。這點可以參考顯式鎖的實現:

java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(Node, int)

/**

* Acquires in exclusive uninterruptible mode for thread already in

* queue. Used by condition wait methods as well as acquire.

*

* @param node the node

* @param arg the acquire argument

* @return {@code true} if interrupted while waiting

*/

final boolean acquireQueued(final Node node, int arg) {

boolean failed = true;

try {

boolean interrupted = false;

for (;;) {

final Node p = node.predecessor();

if (p == head && tryAcquire(arg)) {

setHead(node);

p.next = null; // help GC

failed = false;

return interrupted;

}

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;

}

} finally {

if (failed)

cancelAcquire(node);

}

}

從上面的代碼可以看出,(使用顯式鎖時)被喚醒的線程獲得鎖(tryAcquire調用返回true)之后才被從wait set中移出(setHead調用)。

2、內部鎖僅僅支持非公平鎖調度。顯式鎖既支持公平鎖又支持非公平鎖。

LockSupport.park/upark是在jdk1.5開始引入的,顯式鎖的在實現線程的暫停和喚醒的時候會用到這個兩個方法。而內部鎖是在jdk1.5之前就已經存在的。

【參考資料】

1、黃文海.Java多線程編程實戰指南(核心篇).電子工業出版社,2017

新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!

總結

以上是生活随笔為你收集整理的java设置等待锁的时间_java的锁池和等待池的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。