Java多線程之鎖優化策略 原

鎖的優化策略

    編碼過程中可採取的鎖優化的思路有以下幾種:

    1:減少鎖持有時間 

         例如:對一個方法加鎖,不如對方法中需要同步的幾行代碼加鎖;

    2:減小鎖粒度

        例如:ConcurrentHashMap採取對segment加鎖而不是整個map加鎖,提高併發性;

    3:鎖分離 

        根據同步操作的性質,把鎖劃分爲的讀鎖和寫鎖,讀鎖之間不互斥,提高了併發性。

    4:鎖粗化 

        這看起來與思路1有衝突,其實不然。思路1是針對一個線程中只有個別地方需要同步,所以把鎖加在同步的語句上而不是更大的範圍,減少線程持有鎖的時間;

        而鎖粗化是指:在一個間隔性地需要執行同步語句的線程中,如果在不連續的同步塊間頻繁加鎖解鎖是很耗性能的,因此把加鎖範圍擴大,把這些不連續的同步語句進行一次性加鎖解鎖。雖然線程持有鎖的時間增加了,但是總體來說是優化了的。

    5:鎖消除

        鎖消除是編譯器做的事:根據代碼逃逸技術,如果判斷到一段代碼中,堆上的數據不會逃逸出當前線程(即不會影響線程空間外的數據),那麼可以認爲這段代碼是線程安全的,不必要加鎖。

 

    Java虛擬機中採取的鎖優化策略:

       1:偏向鎖:鎖對象偏向於當前獲得它的線程,如果在接下來的沒有被其他線程請求,則持有該鎖的線程將不再需要進行同步操作(即:持有該鎖的線程在接下來的執行中遇到同步塊時不再需要lock和unlock了,直接執行即可)。當另一個線程申請該鎖時,當前線程的偏向模式纔會結束,讓出該鎖。

       2:輕量級鎖:syncrhoized的底層實現是通過監視器monitor來控制的,而monitorenter與monitorexit這兩個原語是依賴操作系統互斥(mutex)來實現的。

互斥會導致線程掛起,並在較短的時間內又需要重新調度回原線程的,較爲消耗資源。輕量級鎖(Lightweight Locking)利用了CPU原語Compare-And-Swap(CAS,彙編指令CMPXCHG),嘗試在進入互斥前,進行補救,減少多線程進入互斥的機率。

        如果偏向鎖失敗,那麼系統會進行輕量級鎖的操作,使用CAS操作來嘗試加鎖。如果輕量級鎖失敗,才調用系統級別的重量級鎖(syncrhoized)來加鎖。     

       3:自旋鎖:當線程申請鎖時,鎖被佔用,則讓當前線程執行一個忙循環(自旋),看看持有鎖的線程是否會很快釋放鎖。如果自旋後還沒獲得鎖,才進入同步阻塞狀態;

           3.1:自適應自旋:自旋的線程自旋的時間爲同一個鎖上一次線程自旋並獲得鎖的耗時。如果對於這個鎖,自旋很少有成功的,就不自旋了,避免浪費CPU資源。

         爲了儘量避免使用重量級鎖(操作系統層面的互斥),JVM首先會嘗試輕量級鎖,輕量級鎖會嘗試使用CAS操作來獲得鎖,如果輕量級鎖獲得失敗,說明存在競爭。但是也許很快就能獲得鎖,就會嘗試自旋鎖,將線程做幾個空循環,每次循環時都不斷嘗試獲得鎖。如果自旋鎖也失敗,那麼只能升級成重量級鎖。

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