溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java?synchronized輕量級鎖如何實現(xiàn)

發(fā)布時間:2023-02-13 09:34:33 來源:億速云 閱讀:157 作者:iii 欄目:開發(fā)技術

這篇“Java synchronized輕量級鎖如何實現(xiàn)”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Java synchronized輕量級鎖如何實現(xiàn)”文章吧。

一、什么是輕量級鎖

輕量級鎖是JDK 6之中加入的新型鎖機制,它名字中的“輕量級”是相對于使用monitor的傳統(tǒng)鎖而言的。輕量級鎖指的是存在多線程競爭,但是任意時刻最多只允許一個線程競爭獲得鎖,即不存在鎖競爭太過激烈的情況,輕量級鎖情況下,線程不會發(fā)生阻塞。

二、為什么引入輕量級鎖

輕量級鎖考慮的是競爭鎖對象的線程不多,而且線程持有鎖的時間也不長的場景。因為阻塞線程需要CPU從用戶態(tài)轉到內(nèi)核態(tài),代價比較大,如果剛剛阻塞不久這個鎖就被釋放了,那這個代價就有點得不償失了,因此這個時候就干脆不阻塞這個線程,讓它自旋這等待鎖的釋放。

三、輕量級鎖的升級時機

主要有兩個:

1)、關閉偏向鎖功能

使用 -XX:-UseBiasedLocking參數(shù)關閉偏向鎖,此時默認進入輕量級鎖;

2)、多個線程競爭偏向鎖

偏向鎖狀態(tài)下,由于別的線程嘗試競爭偏向鎖,并且CAS更新MarkWord中線程ID失敗,此時發(fā)生【偏向鎖 -> 輕量級鎖】升級;

舉個例子:

1、線程A先獲取到鎖對象,線程B又過來嘗試競爭這個鎖,此時該鎖已是偏向鎖偏向線程A了;

2、線程B嘗試執(zhí)行CAS去替換鎖對象MarkWord中線程ID,看下能不能獲取到鎖;

3、如果線程B的CAS成功了,說明此時線程A執(zhí)行完了同步塊代碼,這個時候線程B會直接替換鎖對象MarkWord中線程ID為自己的線程ID,該鎖不會發(fā)生升級,還是處于偏向鎖狀態(tài);

4、如果線程B的CAS失敗了,說明線程A還沒執(zhí)行完同步塊代碼,這個時候,偏向鎖就會升級為輕量級鎖(偏向鎖標識置為0,同步鎖標識置為00),這個輕量級鎖由原來持有偏向鎖的線程A持有,繼續(xù)執(zhí)行同步代碼,此時正在競爭的線程B會進入CAS自旋等待獲取這個輕量級鎖;

Java?synchronized輕量級鎖如何實現(xiàn)

Java?synchronized輕量級鎖如何實現(xiàn)

四、輕量級鎖的演示

前面我們了解到,當關閉偏向鎖功能的時候,默認獲取的是輕量級鎖。所以我們這里添加運行時參數(shù) -XX:-UseBiasedLocking參數(shù)禁用偏向鎖。

public class LightweightLockDemo01 {
    public static void main(String[] args) {
        // 關閉偏向鎖,默認進入輕量級鎖
        Object objLock = new Object();
        new Thread(() -> {
            synchronized (objLock) {
                System.out.println(ClassLayout.parseInstance(objLock).toPrintable());
            }
        }, "t1").start();
    }
}

Java?synchronized輕量級鎖如何實現(xiàn)

可以看到,對象頭最后三位為“000”,表示當前獲取的是一把輕量級鎖。

五、輕量級鎖的原理

輕量級鎖的加鎖

1)、JVM會在當前線程的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用于存儲鎖對象目前的Mark Word的拷貝(官方稱為Displaced Mark Word)。若一個線程獲得鎖時發(fā)現(xiàn)是輕量級鎖,它會將對象的Mark Word復制到棧幀中的鎖記錄Lock Record中(Displaced Mark Word里面);

2)、線程嘗試利用CAS操作將對象的Mark Word更新為指向Lock Record的指針,如果成功表示當前線程競爭到鎖,則將鎖標志位變成00,執(zhí)行同步操作;

3)、如果失敗,表示MarkWord已經(jīng)被替換成了其他線程的鎖記錄,說明在與其他線程搶占競爭鎖,當前線程就嘗試使用自旋來獲取鎖;

注意,JVM采用的是自適應自旋,也就是說,自適應意味著自旋的次數(shù)不是固定不變的,JVM會根據(jù)同一個鎖上一次自旋的時間以及擁有鎖線程的狀態(tài)來決定到底需要自旋多少次。JVM針對那些很少會自旋成功的線程,那么下次會減少自旋的次數(shù)甚至壓根不自旋,避免CPU空轉。

輕量級鎖的釋放

輕量級鎖的釋放也是通過CAS操作來進行的,當前線程使用CAS操作將Displaced Mark Word的內(nèi)存復制回鎖對象的MarkWord中,如果CAS操作替換成功,則說明釋放鎖成功;如果CAS自旋多次還是替換失敗的話,說明有其他線程嘗試獲取該鎖,則需要將輕量級鎖膨脹升級為重量級鎖;

六、輕量級鎖升級為重量級鎖的流程

Java?synchronized輕量級鎖如何實現(xiàn)

七、輕量級鎖的優(yōu)缺點

優(yōu)點

在多線程交替執(zhí)行同步塊的情況下,可以避免重量級鎖引起的性能消耗;

缺點

如果長時間自旋后還沒競爭到鎖,將會過度耗費CPU,即CPU空轉。

以上就是關于“Java synchronized輕量級鎖如何實現(xiàn)”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關的知識內(nèi)容,請關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI