Java中鎖的四種狀態以及鎖升級過程


Java中加鎖的最簡單方式就是加synchronized關鍵字,但它是一種重量級鎖,會涉及到操作系統狀態的切換影響效率,所以JDK1.6中對synchronized進行了各種優化,為了能減少獲取和釋放鎖帶來的消耗引入了偏向鎖和輕量鎖。

Synchronized 優化

鎖升級

在Java中鎖的狀態一共有四種,級別由低到高分別是:無鎖狀態、偏向鎖狀態、輕量級鎖狀態、重量級鎖狀態,這幾個狀態會隨着競爭情況逐漸升級。

1. 對象頭

在Java中鎖不是某一個具體的實物資源,而是對象上的某個標記,而這個標記就記錄在對象頭上。

Mark Word(對象頭)內部:

2. 無鎖

對象頭中有1bit來表示是否是偏向鎖,2bit存放鎖標志位,偏向鎖位與鎖標志位合起來“001”就代表無鎖。無鎖就是沒有對任何資源進行鎖定,所有線程都能訪問並修改資源。

3. 偏向鎖

對象頭中記錄了獲得偏向鎖的線程ID,偏向鎖與鎖標志位合起來“101”就代表偏向鎖。

為什么要引入偏向鎖?

有研究發現大多數時候是不存在鎖競爭的,常常是一個線程多次獲得同一個鎖,因此如果每次都要競爭鎖會增大很多沒有必要付出的代價,為了降低獲取鎖的代價,才引入的偏向鎖。

偏向鎖的升級

當線程訪問代碼塊並獲取鎖對象時,會將獲得鎖的線程ID寫入到鎖對象Mark Word中。當線程訪問資源結束后,不會主動釋放鎖。當線程再次需要訪問資源時,JVM就會通過Mark Word中記錄的線程ID判斷是否是當前線程,如果是就繼續訪問資源,無需使用CAS來加鎖、解鎖。
所以在沒有其他線程參與競爭時,鎖就一直偏向被當前線程持有,當前線程就可以一直占用資源或者執行代碼。

如果不一致,需要查看Mark Word中記錄的線程是否存活:

  • 如果沒有存活,那么鎖對象被重置為無鎖狀態,其它線程可以競爭將其設置為偏向鎖
  • 如果存活,那么立刻查找該記錄線程的棧幀信息
    • 如果該記錄線程還需要繼續持有這個鎖對象,那么會撤銷偏向鎖,升級為輕量級鎖
    • 如果該記錄線程不再使用該鎖對象,那么將鎖對象狀態設為無鎖狀態,重新偏向新的線程

4. 輕量級鎖(自旋鎖)

一旦有另外一個線程參與鎖競爭,偏向鎖就會升級為輕量級鎖(自旋鎖),此時撤銷偏向鎖,鎖標志位變為“00”。

為什么要引入輕量級鎖?

輕量級鎖考慮的是競爭鎖對象的線程不多,而且線程持有鎖的時間也不長的情景。

因為阻塞線程需要CPU從用戶態轉到內核態,代價較大,如果剛剛阻塞不久這個鎖就被釋放了,那這個代價就有點得不償失了,因此這個時候就干脆不阻塞這個線程,讓它自旋這等待鎖釋放。

輕量級鎖的升級

競爭的兩個線程都在各自的線程棧幀中生成一個Lock Record空間,用於存儲鎖對象目前Mark Word的拷貝(稱為DisplacedMarkWord),用CAS操作將Mark Word設置為指向自己這個線程的Lock Record指針,設置成功者獲得鎖,其他參與競爭的線程如果未獲取到鎖,則會一直處於自旋等待的狀態,直到競爭到鎖。

但是如果自旋的時間太長也不行,因為自旋是要消耗CPU的,因此自旋的次數是有限制的,比如10次或者100次。當競爭的線程自旋次數到了,然而持有鎖的線程還沒有釋放鎖,這個時候輕量級鎖就會膨脹為重量級鎖。重量級鎖把除了擁有鎖的線程都阻塞,防止CPU空轉。

5. 重量級鎖

長時間的自旋操作是很消耗CPU資源的,為了避免這種盲目的消耗,JVM會在有線程超過10次自旋,或者自旋次數超過CPU核數的一半(JDK1.6以后加入了自適應自旋-Adaptive Self Spinning,由JVM自己控制自旋次數)時,會升級到重量級鎖。

重量級鎖底層是依賴操作系統的mutex互斥鎖,也就是有操作系統來負責線程間的調度。

重量級鎖減少了自旋鎖帶來的CPU消耗,但是由於操作系統調度線程帶來的線程阻塞會使程序響應速度變慢。

6. 偏向鎖、輕量級鎖、重量級鎖的對比

鎖粗化

按理來說,同步塊的作用范圍應該盡可能小,僅在共享數據的實際作用域中才進行同步,這樣做的目的是為了使需要同步的操作數量盡可能縮小,縮短阻塞時間,如果存在鎖競爭,那么等待鎖的線程也能盡快拿到鎖。但是加鎖解鎖也需要消耗資源,如果存在一系列的連續加鎖解鎖操作,可能會導致不必要的性能損耗。

鎖粗化就是將多個連續的加鎖、解鎖操作連接在一起,擴展成一個范圍更大的鎖,避免頻繁的加鎖解鎖操作。

鎖消除

Java虛擬機在JIT編譯時(可以簡單理解為當某段代碼即將第一次被執行時進行編譯,又稱即時編譯),通過對運行上下文的掃描,經過逃逸分析,去除不可能存在共享資源競爭的鎖,通過這種方式消除沒有必要的鎖,可以節省毫無意義的請求鎖時間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM