JVM鎖優化

JVM的鎖優化

鎖優化技術(HotSpot虛擬機而言)包括適應性自旋、鎖消除、鎖粗化、輕量級鎖和偏向鎖等。這些技術都是爲了在線程之間更高效地共享數據以及解決競爭問題,從而提升程序效率。數組

自旋鎖

什麼是自旋鎖?

若是線程獲取不到鎖,第一時間不是去切換系統態進行等待,而是作一個循環操做,去等到鎖的釋放,循環到必定的次數終止循環,調入系統調用。爲了讓線程等待,而不是阻塞,讓線程執行一個忙循環(自旋),這就是自旋鎖。多線程

爲何消耗CPU而不是等待?

自旋鎖的優化主要是爲了減小了線程切換帶來的消耗。app

自旋鎖適應的場景

自旋鎖適合那些線程佔用鎖時間短的場景。性能

什麼是自適應自旋鎖?

JDK1.6加入了自適應自旋鎖。顧名思義,若是在同一個鎖對象上,自旋等待剛剛成功得到過鎖,而且持有鎖的線程正在運行,那麼虛擬機就會認爲此次自旋也頗有可能再次成功,並將自旋等待時間延長。若是對於某個鎖,自旋不多成功,那麼在以後獲取該鎖時可能會放棄不自旋直接掛起線程。優化

鎖消除

什麼是鎖消除?

指虛擬機即時編譯器在運行時,對一些代碼上要求同步,可是被檢測到不可能存在共享數據競爭時,把鎖進行消除。操作系統

怎樣判斷哪些代碼能夠進行鎖消除?

鎖消除的主要判斷依據來源於逃逸分析的數據支持,若是判斷在一段代碼中,堆上的全部數據都不會逃逸出去從而被其餘線程訪問到,那就能夠把它們當作棧上數據對待,認爲它們是線程私有的,同步加鎖就無需進行。線程

鎖粗化

什麼是鎖粗化?

若是一系列的連續動做都對同一對象反覆加鎖和解鎖,甚至加鎖操做時出如今循環體中的,那即便沒有線程競爭,頻繁地進行互斥同步操做也會致使沒必要要的性能損耗,好比連續的append()方法。指針

輕量級鎖和偏向鎖

在說輕量級鎖和偏向鎖以前,咱們要先了解一下HotSpot虛擬機中對象的對象頭。對象

HotSpot虛擬機的對象頭分爲兩部分信息:編譯器

  • 第一部分用域存儲對象自身的運行時數據(Mark Word),如哈希碼、GC分代年齡等,他是實現輕量級鎖和偏向鎖的關鍵。
  • 另外一部分用於存儲只想方法區對象類型的指針,若是是數組對象,還有一個額外部分存儲數組長度。

因此,咱們來看一下對象頭的Mark Word中的存儲內容有哪些?

存儲內容 標誌位 狀態 用處
對象哈希碼,對象分代年齡 01 未鎖定 狀態
指向鎖記錄的指針 00 輕量級鎖定 狀態
指向重量級鎖的指針 10 膨脹 狀態
空,不須要記錄信息 11 GC標記 狀態
偏向線程ID,偏向時間戳、對象分代年齡 01 可偏向 狀態

什麼是CAS操做?

CAS是英文單詞CompareAndSwap的縮寫,中文意思是:比較並替換。簡單來講,CAS整個比較並替換的操做是一個原子操做。

輕量級鎖

什麼是輕量級鎖?

他的意思是在沒有多線程競爭的前提下,減小傳統的重量級鎖使用操做系統互斥量產生的消耗

輕量級鎖的執行過程?

加鎖過程:

  • 進入同步塊的時候,若是此同步對象沒有被鎖定(鎖標誌位爲「01」狀態),虛擬機首先將在當前線程的幀棧中創建一個名爲「鎖空間」(Lock Record)的空間,用於存儲鎖對象目前Mark Word的拷貝(這份拷貝叫Displaced Mark Word)
  • 虛擬機將使用CAS操做嘗試將對象的Mark Word更新爲指向Lock Record的指針
    • 若是成功,這個線程就有了該對象的輕量級鎖,Mark Word的鎖標誌位變爲「00」
    • 若是失敗,虛擬機先檢查對象的Mark Word是否指向當前線程的棧幀
      • 若是指向當前線程幀棧就說明該線程獲取到了該鎖,可進入同步塊繼續執行
      • 若沒指向當前線程的幀棧,表示這個鎖對象被其餘線程佔用,這時輕量級鎖再也不有效,要膨脹爲重量級鎖,鎖的標誌位變爲「10」,Mark Word 中存儲的就是指向重量級鎖(互斥量)的指針,後面等待的線程也要進入阻塞狀態

解鎖過程:

  • 若是對象的Mark Word仍然指向線程的鎖記錄,就用CAS操做把對象當前Mark Word和線程中複製的Displaced Mark Word替換回來
    • 替換成功,同步完成
    • 替換失敗,有其餘線程嘗試獲取該鎖,釋放鎖的同時,喚醒被掛起的線程。

輕量級鎖的使用場景

提高程序同步性能的依據是「對於絕大部分的鎖,在整個同步週期內都是不存在競爭的」。

若是沒有競爭,輕量級鎖使用CAS操做避免了使用互斥量的開銷。

但若是存在鎖競爭,除了互斥量的開銷外,還額外發生了CAS操做,所以在有競爭的狀況下,輕量級鎖會比傳統的重量級鎖更慢。

偏向鎖

什麼是偏向鎖?

消除數據在無競爭狀況下的同步原語,進一步提升程序的運行性能。簡單來講就是**在無競爭的狀況下把整個同步都消除掉,連CAS操做都不作。**就是說當一個線程率先獲取到這個鎖後,若是該鎖沒有被其餘線程獲取,那麼持有偏向鎖的線程將永遠不須要同步。

工做過程

  • 當鎖對象第一次被線程獲取的時候,虛擬機將會把對象頭中的標誌位設爲"01",使用CAS操做把獲取到的鎖的線程ID記錄到Mark Word中,若是CAS操做成功,持有偏向鎖的線程之後每次進入這個鎖相關的同步塊時,都再也不進行任何操做
  • 當有另外一個線程去嘗試獲取這個鎖時,偏向模式宣告結束。根據鎖對象目前是否處於被鎖定的狀態,撤銷偏向後恢復到未鎖定或輕量級鎖定的狀態,後續的同步操做就如上面介紹的輕量級鎖那樣執行

偏向鎖的使用場景

能夠提升帶有同步但無競爭的程序性能

和輕量級鎖同樣,若是這個同步塊可能不少時候都是多個線程同時訪問的話,那麼偏向鎖甚至會增長時耗

總結

JVM對鎖進行了優化,包括自旋鎖(自適應自旋鎖)、鎖粗化、輕量級鎖、偏向鎖。然後二者會由於競爭的多少而產生性能的變化。

相關文章
相關標籤/搜索