【多線程與併發】鎖的種類以及鎖的優化

多線程中鎖的種類

 

一、可重入鎖

ReentrantLock和synchronized都是可重入鎖

如果當前線程已經獲得了某個監視器對象所持有的鎖,那麼該線程在該方法中調用另外一個同步方法也同樣持有該鎖。

比如:

public synchronized void test(){
    xxxxxx;
    test2();
}

public synchronized void test2(){
    yyyyyy;
}

在上面代碼段中,執行test方法需要獲得對象作爲監視器的對象鎖,但方法中又調用了test2的同步方法。

如果鎖時具有可重入性的話,那麼線程在調用test2時並不需要再次獲得當前對象的鎖,可以直接進入test2方法進行操作。

可重入鎖最大的作用是避免死鎖。如果鎖時不具有可重入性的話,那麼該線程在調用test2前會等待當前對象鎖的釋放,實際上該對象鎖已被當前線程所持有,不可能再次獲得,那麼線程在調用同步方法、含有鎖的方法時就會產生死鎖

二、可中斷鎖

顧名思義,就是可以相應中斷的鎖。

在Java中,synchronized是不可中斷鎖,而Lock是可中斷鎖lockInterruptibly()的用法已經體現了Lock的可中斷性。如果某一線程A正在執行鎖的中的代碼,另一線程B正在等待獲取該鎖,可能由於等待時間過長,線程B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在別的線程中斷它,這就是可中斷鎖。

三、公平鎖

在Java中,synchronized就是非公平鎖,它無法保證等待的線程獲取鎖的順序。而對於ReentrantLock和ReentrantReadWriteLock,它默認情況下是非公平鎖,但是可以設置爲公平鎖。

公平鎖即儘量以請求鎖的順序來獲取鎖。比如同是有多個線程在等待一個鎖,當這個鎖被釋放時,等待時間最久的線程(最先請求的線程)會獲得該鎖,這種就是公平鎖。

四、讀寫鎖

正因爲有了讀寫鎖,才使得多個線程之間的讀操作不會發生衝突。ReentrantLock就是讀寫鎖,它是一個接口,ReentrantReadWrite實現了這個接口。可以通過readLock()獲取讀鎖,通過writeLock獲取寫鎖()。

 

鎖優化

 

一、自旋鎖

爲了讓線程實現等待,然線程執行一個忙循環(自旋)。需要物理機器上有一個以上的處理器。自旋等待雖然避免了線程切換的開銷,但是它是要佔用處理器時間的,所以如果鎖被佔用的時間很多,自旋等待的效果就會非常好,反之自旋的線程只會拜拜消耗處理器資源。自旋次數的默認值是10次,可以使用參數-XX:PreBlockSpin來更改。

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

二、鎖清除

指虛擬機即時編譯器在運行時,對一些代碼上要求同步,但是被檢測到不可能存在共享數據競爭的鎖進行清除(逃逸技術分析:在堆上的所有數據都不會逃逸出去被其他線程訪問到,可以把他們當做棧上數據對待)。

三、鎖粗化

如果虛擬機探測到有一串零碎的操作都對同一個對象加鎖,將會把加鎖同步的範圍擴展到整個操作序列的外部。

四、輕量級鎖

在代碼中進入同步塊時,如果此同步對象沒有被鎖定,虛擬機首先將在當前線程的桟幀中建立一個名爲鎖記錄(Lock Record)的空間,用於存儲所對象目前的Mark Word的拷貝。然後虛擬機將使用CAS操作嘗試將對象的Mark Word更新爲執行Lock Record的指針。如果成功,那麼這個線程就擁有了該對象的鎖。如果更新操作失敗,虛擬機首先會檢查對象的Mark Work是否指向當前線程的桟幀,如果是就說明當前線程已經擁有了這個對象的鎖,否則說明這個對象已經被其他線程搶佔。如果有兩條以上的線程爭用同一個鎖,那輕量級鎖就不再有效,要膨脹爲重量級鎖。

解鎖過程:如果對象的Mark Word仍然指向着線程的鎖記錄,那就用CAS操作把對象當前的Mark Word和線程中複製的Displaced Mark Word替換回來,如果替換成功,整個過程就會完成。如果失敗,說明有其他線程嘗試過獲取該鎖,那就要在釋放鎖的同時,喚醒被掛起的線程。

輕量級鎖的依據:對於絕大部分的鎖,在整個同步週期內都是不存在競爭的。
傳統鎖(重量級鎖)使用操作系統互斥量來實現。

HotSpot虛擬機的對象的內存佈局:對象頭(Object Header)分爲兩部分信息嗎,第一部分(Mark Word)用於存儲對象自身的運行時數據,另一個部分用於存儲指向方法區對象數據類型的指針,如果是數組的話,還會由一個額外的部分用於存儲數組的長度。

32位HotSpot虛擬機中對象被鎖定的狀態下,Mark Word的32個Bits空間中25位用於存儲對象哈希碼,4位存儲對象分代 年齡,2位存儲鎖標誌位,1位固定位0.

HotSpot虛擬機對象頭Mark Word

存儲內容 標誌位 狀態
對象哈希碼、對象、分代年齡 01 未鎖定
指向鎖記錄的指針 00 輕量級鎖定
指向重量級鎖的指針 10 膨脹(重量級鎖)

                      空,不記錄信息

11 GC標記
偏向線程ID,偏向時間戳、對象分代年齡 01 可偏向

 

 

 

 

 

 

 

五、偏向鎖

目的是消除在無競爭情況下的同步原語,進一步提高程序的運行性能。鎖會偏向第一個獲得它的線程,如果在接下來的執行過程中,該鎖沒有被其他線程獲取,則持有鎖的線程將永遠不會需要在進行同步。

當鎖第一次被線程獲取的時候,虛擬機將會把對象頭中的標記位設爲01,同時使用CAS操作把獲取到這個鎖的線程ID記錄在對象的Mark Word之中,如果成功,持有偏向鎖的線程以後每次進入這個鎖相關的同步塊時,都可以不進行任何同步操作。

當有另一個線程去嘗試獲取這個鎖時,偏向模式就宣告結束。根據鎖對象目前是否處於被鎖定的狀態,撤銷偏向後恢復到未鎖定或輕量級鎖定狀態。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章