1. 程式人生 > >JVM(五)----------------執行緒安全之鎖機制

JVM(五)----------------執行緒安全之鎖機制

鎖機制是JAVA虛擬機器實現執行緒安全的方法之一。在這裡介紹幾個鎖優化

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

1.自旋鎖與自適應自旋

為什麼選擇自旋去消耗CPU而不直接等待?

互斥同步對效能最大的影響是阻塞的實現,掛起執行緒和恢復執行緒的操作都需要轉入核心態中完成,這些操作給作業系統的併發效能帶來了很大的壓力。 如果鎖定狀態只維持很短的一段時間,為了這段時間去掛起和恢復執行緒並不值得。  但是,自旋不能代替阻塞,因為需要佔用處理器時間。

在互斥同步的時候,為了消除執行緒切換帶來的效能消耗,讓等待鎖的執行緒執行一個忙迴圈(自旋),而不放棄處理器的執行時間,看看持有鎖的執行緒是否很快就會釋放鎖。這就是自旋鎖。

自旋等待雖然避免了執行緒切換的開銷,但如果鎖被佔用很長時間,自旋的執行緒只會白白浪費處理器資源,所以自旋等待的時間要有一定限度。如果自旋超過了限定的次數仍然沒有成功獲得鎖,就使用傳統的方式掛起執行緒。自旋預設的次數是10,可以通過引數-XX:PreBlockSpin更改。

自適應的自旋鎖意味著自旋時間不再固定,而是由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態來決定。

2.鎖消除

鎖消除是指虛擬機器即時編譯器在執行時,對一些程式碼上要求同步,但是被檢測到不可能存在共享資料競爭的鎖進行消除。鎖消除的主要判斷依據來源於逃逸分析的資料支援,如果判斷在一段程式碼中,堆上的所有資料都不會逃逸出去從而被其他執行緒訪問到,那就可以把它們當做棧上資料對待,認為它們是執行緒私有的,同步加鎖就無需進行。 這種情況主要是一些Java API中類自己的同步的消除,因為一般在編寫程式碼時都會清除哪些資料存在競爭。

3.輕量級鎖

在沒有多執行緒競爭的前提下,減少傳統的重量級鎖使用作業系統互斥量產生的效能消耗。

輕量級鎖是通過物件頭儲存區域狀態實現的,物件頭的記憶體佈局,物件頭分為兩部分資訊:

(1)第一部分用於儲存物件自身的執行時資料,如雜湊碼,GC分代年齡等,這部分資料的長度在32位和64位的虛擬機器中分為32bit和64bit,官方稱為“Mark Word”,它是實現輕量級鎖和偏向鎖的關鍵。

(2)另外一部分用於儲存指向方法區物件型別資料的指標,如果是陣列物件的話,還會有一個額外的部分用於儲存陣列長度

 輕量級鎖的加鎖過程

  • 在程式碼塊進入同步塊的時候,如果此同步物件沒有被鎖定,虛擬機器首先將在當前執行緒的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用於儲存鎖物件目前的Mark Word的拷貝(官方把這份拷貝加了一個Displaced字首,即Displaced字首,即Displaced Mark Word)
  • 虛擬機器將使用CAS操作嘗試將物件的Mark Word更新為指向Lock Record 的指標。如果這個更新動作成功了,那麼這個執行緒就擁有了該物件的鎖,並且物件Mark Word的鎖標誌位將轉變為“00”,即表示此物件處於輕量級鎖定狀態
  • 如果這個更新操作失敗了,虛擬機器首先會檢查物件的Mark Word 是否指向當前執行緒的棧幀,如果只說明當前執行緒已經擁有了這個物件鎖,那就可以直接進入同步塊繼續執行,否則說明這個鎖物件已經被其他執行緒搶佔了。如果有兩條以上的執行緒爭用同一個鎖,那輕量級鎖不再有效,要膨脹為重量級鎖,鎖標誌的狀態值變為“10”,Mark Word 中儲存的就是指向重量級鎖(互斥量)的指標,後面等待的執行緒也要進入阻塞狀態

輕量級鎖的解鎖過程

  • 解鎖過程也是通過CAS操作進行的,如果物件的Mark Word 任然指向著執行緒的鎖記錄,那就用CAS操作把物件當前的Mark Word和執行緒中複製的Displaced Mark Word替換回來,如果替換成功,整個同步過程就完成了。如果替換失敗,說明有其他執行緒嘗試過獲取該鎖,那就要在釋放鎖的同時,喚醒被掛起的執行緒。

輕量級鎖能提升程式同步效能的依據是“對於絕大部分鎖,在整個同步週期內都是不存在競爭的”,這是一個經驗資料。如果沒有競爭,輕量級鎖使用了CAS操作避免了使用互斥量的開銷,但如果存在鎖競爭,除了互斥量的開銷外,還額外發生了CAS操作,因此在有競爭的情況下,輕量級鎖會比傳統重量級鎖更慢。

4.偏向鎖 

 輕量級鎖是在無競爭情況下使用CAS操作去消除同步使用的互斥量,那偏向鎖就是在無競爭的情況下把整個同步都消除掉,連CAS操作都不做了。

偏向鎖中的“偏向”是指鎖偏向於第一個獲取它的執行緒,如果在接下來的執行過程中,該鎖沒有被其他的執行緒獲取,則持有偏向鎖的執行緒永遠不需要同步。

偏向鎖的原理:當鎖物件第一次被執行緒獲取的時候,虛擬機器將Mark World的標誌位設為偏向模式(01),同時使用CAS操作將獲取到該鎖的執行緒ID記錄在Mark World之中。如果CAS操作成功,持有偏向鎖的執行緒以後每次進入這個鎖的同步塊時,虛擬機器都不再進行任何同步操作。當有另外的執行緒嘗試獲取該鎖時,偏向模式就結束了。此時,根據鎖物件目前是否處於被鎖定的狀態,撤銷偏向後恢復到未鎖定或者輕量級鎖的狀態。後續的操作就如同輕量級鎖那樣執行。

偏向鎖可以提高帶有同步但無競爭的程式效能,是一個帶有效益權衡(Trade Off)性質的優化,它並不一定總是對程式執行有利。如果程式中總是被多個不同的執行緒訪問,那偏向模式就是多餘的。