-xx:+usebiasedlocking:開啟偏向鎖,-xx:-usebiasedlocking:關閉偏向鎖,-xx:biasedlockingstartupdelay=0:設定偏向鎖延遲為0,即關閉延遲。
偏向鎖是基於object的object header中的markword來實現的,64位作業系統中,object header 占用128bit,markwork佔64bit。
圖中前8個位元組即為markword。可看到有個101,其餘都是0,這表示此物件為可偏向但未偏向狀態,可認為是markwork的初始化的某一種情況。為什麼是某一種情況呢?因為偏向鎖是有延遲的,若過了延遲的時間,物件才例項化,就是這種狀態;若再延遲時間內例項化的物件,其狀態是一種不可偏向的無鎖狀態,如下圖:
其中的001,即為不可偏向的無鎖狀態,此狀態是不可偏向的,所以這裡我們研究的是第一種情況,即101。
當執行緒進入同步塊時,markword中會記錄執行緒id,表示物件鎖偏向了此執行緒id的執行緒:
圖三與圖一比,markword中發生了改變,記錄了偏向的執行緒id,當此執行緒id的執行緒再進入同步塊時,只要比對執行緒id相同,即可獲得物件鎖。這也是偏向鎖相對於重量鎖的優化,效能會提公升很多。但若是別的執行緒id來訪問同步塊,則會先撤銷偏向鎖為無鎖,再膨脹為輕量鎖!
特地說明一下,當呼叫了乙個物件的hashcode方法,markword將不再記錄執行緒id,而記錄物件的hashcode值,這會導致偏向鎖不可用!
當乙個執行緒來訪問同步塊時,發現物件頭的markword已偏向了乙個不是自己的執行緒id,則會先撤銷偏向鎖為無鎖,再cas嘗試將markword的前62位(若呼叫過hashcode方法,其中包含物件的hashcode值),替換成本執行緒棧針的lock_record的位址,替換成功,則獲取到鎖,此過程,將鎖膨脹為輕量鎖!來看下輕量鎖的markword:可發現,markword中清除了之前記錄的lock_record,並還原了之前的62位的資訊(若呼叫過hashcode方法,物件的hashcode值也隨之恢復)以等待其他執行緒來獲取鎖。 此時,物件鎖為無鎖狀態!
但是,若乙個執行緒來獲取鎖,對markword前62位進行cas操作,若此時markword中記錄的是持有鎖的lock_record的位址,那這個執行緒將獲取鎖失敗,接下來進行自旋。若自旋次數超過了設定的閾值,還未cas成功,則會將鎖膨脹為重量級鎖。
上圖中,鎖的狀態變為10,即為重量鎖。當乙個執行緒去獲取物件鎖,發現其狀態為10,則將此執行緒加入到object_monitor的同步佇列中,等待鎖釋放之後去競爭鎖。此時,鎖的效能最低!
我們發現,鎖的膨脹過程,是伴隨著併發度的提公升的。隨著不同的業務場景來使用合適的鎖,以此來提公升jvm的效能! 由於乙個class模板,會生成好多物件。因為偏向鎖->撤銷偏向鎖->無鎖->輕量鎖,這個過程要耗費資源,當超過20個物件執行了這個過程,會進行批量重偏向。過程大致為:class物件的markword的epoch將改為10,並同時這個類的其他還在同步塊的物件的epoch改為10,而不在同步塊的物件不改還為01,執行緒去獲取鎖時,物件的epoch值與class物件的epoch值進行比對,如不一樣,則可進行重偏向,即將偏向鎖的執行緒id變換為另乙個要獲取鎖的執行緒的id。此處,筆者就不再演示。Java輕量鎖 偏向鎖 自旋鎖 重量鎖
巨集觀上分為 悲觀鎖 樂觀鎖 悲觀鎖 認為寫多讀少,每次都會上鎖。樂觀鎖 讀多寫少。自旋鎖 如果持有鎖的執行緒能在很短的時間內釋放資源,那麼那些等待競爭鎖的執行緒就不需要做核心態與使用者態之間的切換進入阻塞狀態,只需要等一等 自旋 等待有鎖的執行緒釋放鎖後即可立即獲取鎖,避免使用者執行緒與核心的切換...
偏向鎖 輕量級鎖 重量級鎖
首先簡單說下先偏向鎖 輕量級鎖 重量級鎖三者各自的應用場景 偏向鎖 只有乙個執行緒進入臨界區 輕量級鎖 多個執行緒交替進入臨界區 重量級鎖 多個執行緒同時進入臨界區。還要明確的是,偏向鎖 輕量級鎖都是jvm引入的鎖優化手段,目的是降低執行緒同步的開銷。比如以下的同步 塊 synchronized l...
偏向鎖 輕量級鎖 重量級鎖
synchronized關鍵字就像是汽車的自動檔,現在詳細講這個過程。一腳油門踩下去,synchronized會從無鎖公升級為偏向鎖,再公升級為輕量級鎖,最後公升級為重量級鎖,就像自動換擋一樣。那麼自旋鎖在 呢?這裡的輕量級鎖就是一種自旋鎖。初次執行到synchronized 塊的時候,鎖物件變成偏...