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操做來得到鎖,若是輕量級鎖得到失敗,說明存在競爭。可是也許很快就能得到鎖,就會嘗試自旋鎖,將線程作幾個空循環,每次循環時都不斷嘗試得到鎖。若是自旋鎖也失敗,那麼只能升級成重量級鎖。

相關文章
相關標籤/搜索