JVM鎖優化以及區別

2022-04-18 14:37:10 字數 2092 閱讀 9895

偏向所鎖,輕量級鎖都是樂觀鎖,重量級鎖是悲觀鎖。 

首先簡單說下先偏向鎖、輕量級鎖、重量級鎖三者各自的應用場景:

還要明確的是,偏向鎖、輕量級鎖都是jvm引入的鎖優化手段,目的是降低執行緒同步的開銷。比如以下的同步**塊:

synchronized (lockobject) 

上述同步**塊中存在乙個臨界區,假設當前存在thread#1和thread#2這兩個使用者執行緒,分三種情況來討論:

sychronized鎖優化解釋1:

上述的情況一是偏向鎖的適用場景,此時當thread#1進入臨界區時,jvm會將lockobject的物件頭mark word的鎖標誌位設為「01」,同時會用cas操作把thread#1的執行緒id記錄到mark word中,此時進入偏向模式。所謂「偏向」,指的是這個鎖會偏向於thread#1,若接下來沒有其他執行緒進入臨界區,則thread#1再出入臨界區無需再執行任何同步操作。也就是說,若只有thread#1會進入臨界區,實際上只有thread#1初次進入臨界區時需要執行cas操作,以後再出入臨界區都不會有同步操作帶來的開銷。

然而情況一是乙個比較理想的情況,更多時候thread#2也會嘗試進入臨界區。若thread#2嘗試進入時thread#1已退出臨界區,即此時lockobject處於未鎖定狀態,這時說明偏向鎖上發生了競爭(對應情況二),此時會撤銷偏向,mark word中不再存放偏向執行緒id,而是存放hashcode和gc分代年齡,同時鎖標識位變為「01」(表示未鎖定),這時thread#2會獲取lockobject的輕量級鎖。因為此時thread#1和thread#2交替進入臨界區,所以偏向鎖無法滿足需求,需要膨脹到輕量級鎖。

再說輕量級鎖什麼時候會膨脹到重量級鎖。若一直是thread#1和thread#2交替進入臨界區,那麼沒有問題,輕量鎖hold住。一旦在輕量級鎖上發生競爭,即出現「thread#1和thread#2同時進入臨界區」的情況,輕量級鎖就hold不住了。 (根本原因是輕量級鎖沒有足夠的空間儲存額外狀態,此時若不膨脹為重量級鎖,則所有等待輕量鎖的執行緒只能自旋,可能會損失很多cpu時間)

sychronized鎖優化解釋2:

乙個物件剛開始例項化的時候,沒有任何執行緒來訪問它的時候。它是可偏向的,意味著,它現在認為只可能有乙個執行緒來訪問它,所以當第乙個執行緒來訪問它的時候,它會偏向這個執行緒,此時,物件持有偏向鎖。偏向第乙個執行緒,這個執行緒在修改物件頭成為偏向鎖的時候使用cas操作,並將物件頭中的threadid改成自己的id,之後再次訪問這個物件時,只需要對比id,不需要再使用cas在進行操作。

一旦有第二個執行緒訪問這個物件,因為偏向鎖不會主動釋放,所以第二個執行緒可以看到物件時偏向狀態,這時表明在這個物件上已經存在競爭了,檢查原來持有該物件鎖的執行緒是否依然存活,如果掛了,則可以將物件變為無鎖狀態,然後重新偏向新的執行緒,如果原來的執行緒依然存活,則馬上執行那個執行緒的操作棧,檢查該物件的使用情況,如果仍然需要持有偏向鎖,則偏向鎖公升級為輕量級鎖,(偏向鎖就是這個時候公升級為輕量級鎖的)。如果不存在使用了,則可以將物件回覆成無鎖狀態,然後重新偏向。     

輕量級鎖認為競爭存在,但是競爭的程度很輕,一般兩個執行緒對於同乙個鎖的操作都會錯開,或者說稍微等待一下(自旋),另乙個執行緒就會釋放鎖。 但是當自旋超過一定的次數,或者乙個執行緒在持有鎖,乙個在自旋,又有第三個來訪時,輕量級鎖膨脹為重量級鎖,重量級鎖使除了擁有鎖的執行緒以外的執行緒都阻塞,防止cpu空轉。

補充:輕量鎖膨脹到重量鎖有兩個條件

1.等待的執行緒自旋超過一定次數。

2.持有鎖的執行緒cas釋放鎖,但是失敗。

解釋:1.很顯然,自旋超過一定次數會消耗cpu資源,乾脆阻塞。

2.當執行緒cas釋放鎖的時候,比較物件頭中的mark word是否指向本執行緒的lock record

(此處認為還要比較物件頭中markword是否和執行緒lock record中的displace mark word相同,我認為是沒道理的,因為此時lock record中的displaced儲存的是物件的hashcode,而物件的mark word中儲存的卻是指向lock record的指標,因此不可能相同。而且此處的cas指得就是用hashcode替換指標)。當發現cas失敗的時候,說明什麼?儘管有乙個執行緒在自旋,但是還是cas失敗,說明競爭比較頻繁,因此公升級成重量鎖,阻塞其他執行緒,自己安安穩穩的釋放掉後再喚醒其他執行緒,然後讓其他執行緒競爭去。

JVM對鎖的優化

作為一款公用的平台,jdk肯定也對併發程式的效能絞盡腦汁,內部也想盡一切辦法來提高併發時候的吞吐量。下面介紹幾種jdk內部的鎖優化策略 一.鎖偏向 二.輕量級鎖 如果偏向鎖失敗,虛擬機器並不會立即掛起執行緒,它還會使用一種稱為輕量級鎖的優化手段。輕量級鎖的操作也很輕便,它只是簡單的將物件的頭部作為指...

jvm隨筆9 鎖優化

1.自旋鎖 問題 掛起和恢復執行緒要轉入核心態中完成,許多應用,共享資料的鎖定狀態只會持續很短一段時間,為了這段時間去掛起和恢復執行緒並不值得。兩個或以上的執行緒並行執行時,可以讓後面請求鎖的那個執行緒等一下,但不放棄處理器的執行時間,看看持有鎖的執行緒是否很快就會釋放鎖。為了讓執行緒等待,只需讓執...

JVM學習(九) 鎖優化

1 高效併發是jdk1.5到jdk1.6的乙個重要改進,出現了適應性自旋 adaptive spinning 鎖消除 lock elimination 鎖粗化 lock coarsening 輕量級鎖 lightweight locking 和偏向鎖 biased locking 等一系列鎖優化技術...