偏向鎖,輕量級鎖與重量級鎖的區別與膨脹

寫在前面

  先依然描述這三個鎖是什麼: 這裏直接從《深刻理解java虛擬機》粘貼過來。java

偏向鎖

  Hotspot 的做者通過以往的研究發現大多數狀況下鎖不只不存在多線程競爭,並且老是由同一線程屢次得到,爲了讓線程得到鎖的代價更低而引入了偏向鎖。當一個線程訪問同步塊並獲取鎖時,會在對象頭和棧幀中的鎖記錄裏存儲鎖偏向的線程 ID,之後該線程在進入和退出同步塊時不須要花費CAS操做來加鎖和解鎖,而只需簡單的測試一下對象頭的Mark Word裏是否存儲着指向當前線程的偏向鎖,若是測試成功,表示線程已經得到了鎖,若是測試失敗,則須要再測試下 Mark Word中偏向鎖的標識是否設置成 1(表示當前是偏向鎖),若是沒有設置,則使用 CAS 競爭鎖,若是設置了,則嘗試使用 CAS 將對象頭的偏向鎖指向當前線程。
  偏向鎖的撤銷:偏向鎖使用了一種等到競爭出現才釋放鎖的機制,因此當其餘線程嘗試競爭偏向鎖時,持有偏向鎖的線程纔會釋放鎖。偏向鎖的撤銷,須要等待全局安全點(在這個時間點上沒有字節碼正在執行),它會首先暫停擁有偏向鎖的線程,而後檢查持有偏向鎖的線程是否活着,若是線程不處於活動狀態,則將對象頭設置成無鎖狀態,若是線程仍然活着,擁有偏向鎖的棧會被執行,遍歷偏向對象的鎖記錄,棧中的鎖記錄和對象頭的Mark Word要麼從新偏向於其餘線程,要麼恢復到無鎖或者標記對象不適合做爲偏向鎖,最後喚醒暫停的線程。安全

輕量級鎖

       輕量級鎖加鎖:線程在執行同步塊以前, JVM會先在當前線程的棧楨中建立用於存儲鎖記錄的空間,並將對象頭中的Mark Word複製到鎖記錄中,官方稱爲Displaced Mark Word。而後線程嘗試使用 CAS 將對象頭中的Mark Word替換爲指向鎖記錄的指針。若是成功,當前線程得到鎖,若是失敗,表示其餘線程競爭鎖,當前線程便嘗試使用自旋來獲取鎖。若是有兩條以上的線程爭用同一個鎖,那輕量級鎖就再也不有效,要膨脹爲量級鎖,鎖標誌的狀態值變爲」10」,Mark Word中存儲的就是指向重量級(互斥量)的指針。多線程

     輕量級鎖解鎖:輕量級解鎖時,會使用原子的 CAS 操做來將Displaced Mark Word替換回到對象頭,若是成功,則表示沒有競爭發生。若是失敗,表示當前鎖存在競爭,鎖就會膨脹成重量級鎖。測試

 

 

我的理解:

        偏向所鎖,輕量級鎖都是樂觀鎖,重量級鎖是悲觀鎖。線程

        一個對象剛開始實例化的時候,沒有任何線程來訪問它的時候。它是可偏向的,意味着,它如今認爲只可能有一個線程來訪問它,因此當第一個線程來訪問它的時候,它會偏向這個線程,此時,對象持有偏向鎖。偏向第一個線程,這個線程在修改對象頭成爲偏向鎖的時候使用CAS操做,並將對象頭中的ThreadID改爲本身的ID,以後再次訪問這個對象時,只須要對比ID,不須要再使用CAS在進行操做。一旦有第二個線程訪問這個對象,由於偏向鎖不會主動釋放,因此第二個線程能夠看到對象時偏向狀態,這時代表在這個對象上已經存在競爭了,檢查原來持有該對象鎖的線程是否依然存活,若是掛了,則能夠將對象變爲無鎖狀態,而後從新偏向新的線程,若是原來的線程依然存活,則立刻執行那個線程的操做棧,檢查該對象的使用狀況,若是仍然須要持有偏向鎖,則偏向鎖升級爲輕量級鎖,(偏向鎖就是這個時候升級爲輕量級鎖的)。若是不存在使用了,則能夠將對象回覆成無鎖狀態,而後從新偏向。指針

        輕量級鎖認爲競爭存在,可是競爭的程度很輕,通常兩個線程對於同一個鎖的操做都會錯開,或者說稍微等待一下(自旋),另外一個線程就會釋放鎖。 可是當自旋超過必定的次數,或者一個線程在持有鎖,一個在自旋,又有第三個來訪時,輕量級鎖膨脹爲重量級鎖,重量級鎖使除了擁有鎖的線程之外的線程都阻塞,防止CPU空轉。對象

相關文章
相關標籤/搜索