日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

不吃飯也要掌握的Synchronized鎖升級過程

來源: 責編: 時間:2023-11-08 09:10:54 260觀看
導讀一、前言在面試題中經常會有這么一道面試題,談一下synchronized鎖升級過程?之前背了一些,很多文章也說了,到底怎么什么條件才會觸發升級,一直不太明白。實踐是檢驗真理的唯一標準,今天就和大家一起實踐一下,什么條件才會升級

AeC28資訊網——每日最新資訊28at.com

一、前言

在面試題中經常會有這么一道面試題,談一下synchronized鎖升級過程?AeC28資訊網——每日最新資訊28at.com

之前背了一些,很多文章也說了,到底怎么什么條件才會觸發升級,一直不太明白。AeC28資訊網——每日最新資訊28at.com

實踐是檢驗真理的唯一標準,今天就和大家一起實踐一下,什么條件才會升級!AeC28資訊網——每日最新資訊28at.com

二、為什么會有鎖升級過程?

在實踐之前,我們先一步步的來了解!為什么要升級呢?AeC28資訊網——每日最新資訊28at.com

在JDK1.6之前,synchronized的性能一直沒有ReentrantLock性能高,主要是因為synchronized涉及到用戶態和內核態的切換,這個是在操作系統和硬件是非常消耗資源的。AeC28資訊網——每日最新資訊28at.com

經過不斷的統計分析,發現大部分時間一個鎖都是一個線程去獲取,如果只有一個線程來嘗試加鎖,就是重量級鎖,顯而浪費資源。AeC28資訊網——每日最新資訊28at.com

「總之,鎖的升級過程是為了提高多線程環境下的性能和吞吐量,減少同步操作的開銷,并盡量避免線程切換的開銷。Java虛擬機根據線程競爭的情況和鎖的使用情況自動進行鎖的升級和降級,以優化多線程程序的性能。」AeC28資訊網——每日最新資訊28at.com

此時,就引入了很多鎖類型,下面我們來具體看看!AeC28資訊網——每日最新資訊28at.com

三、鎖分類

偏向鎖:偏向鎖是為了解決單線程訪問的場景,偏向鎖允許第一個訪問共享資源的線程獲得鎖,把線程id存到對象頭中,后續的訪問可以直接獲得鎖,而不需要競爭。AeC28資訊網——每日最新資訊28at.com

輕量級鎖:當一個或多個線程嘗試獲取同一個鎖時,偏向鎖會升級為輕量級鎖。輕量級鎖采用CAS(Compare and Swap)操作來減小鎖的競爭。采用自適應自旋!AeC28資訊網——每日最新資訊28at.com

重量級鎖:操作系統的調度器會介入,將競爭鎖的線程掛起,直到鎖被釋放為止,重量級鎖的開銷相對較高。AeC28資訊網——每日最新資訊28at.com

「補充:」AeC28資訊網——每日最新資訊28at.com

「自適應自旋的基本思想是根據鎖的爭用情況,決定線程是否應該自旋等待,以及自旋等待的時間,一般情況為自旋10次。」AeC28資訊網——每日最新資訊28at.com

四、對象內存結構

我們在說鎖的升級過程之前,需要了解一下對象的內存結構,因為在鎖升級過程中會往對象頭上進行填充信息!一個對象分為:對象頭、實例數據、對其填充位三部分組成。AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

我們本次主要用到對象頭,我們再看一下詳細的對象頭信息里有什么:AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

四、圖解鎖升級過程

先來一個簡圖:AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

下面引用百度上的一張詳細一點的圖:AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

我們來詳細的說一下鎖的升級過程,在每一個鎖切換時的條件是什么?AeC28資訊網——每日最新資訊28at.com

在JDK8時,偏向鎖默認是在程序啟動后4s自動開啟的,在JKD15之后默認是不開啟的!AeC28資訊網——每日最新資訊28at.com

可以設置無延遲時間啟動:-XX:BiasedLockingStartupDelay=0也可以不啟動偏向鎖:-XX:-UseBiasedLocking = false。AeC28資訊網——每日最新資訊28at.com

直接說有點不形象,我們下面結合代碼來實戰,看一下具體情況!AeC28資訊網——每日最新資訊28at.com

五、實戰鎖升級過程

為了我們能夠查詢對象結構,我們需要引入jar幫助我們查看!AeC28資訊網——每日最新資訊28at.com

1、導入依賴

「注意」:不要使用高版本的,高版本不顯示2進制,不好觀察!AeC28資訊網——每日最新資訊28at.com

<dependency>    <groupId>org.openjdk.jol</groupId>    <artifactId>jol-core</artifactId>    <version>0.10</version></dependency>

2、實戰代碼和解析

我們來從序號1開始,上面也說了默認4s后開啟偏向鎖,我們會發現序號1打印的對象頭序號為:001我們的對象大小為20,內部幫我們補位來滿足是8的倍數。方便操作系統進行尋址,不會有碎片組合!這個大家可以詳細搜一下,這里就一帶而過了哈!AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

此時我們睡眠6s,包裝偏向鎖開啟成功!AeC28資訊網——每日最新資訊28at.com

我們來到序號2,開啟了偏向鎖,我們發現對象頭序號為:101。AeC28資訊網——每日最新資訊28at.com

「節點:從無鎖到偏向鎖切換的條件:JDK8中默認4s后開啟,JDK15需要手動開啟」。AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

來到序號3和4一起說吧,當我們進行synchronized加鎖時,對象的頭信息中會記錄上當前線程的id,下面再有加鎖的,直接判斷線程id是否一致,一致直接進入代碼塊。不一致后面再說!我們發現在序號4時,已經出了代碼塊,在此查詢加鎖的對象,信息依舊在,不會進行移除,這就是偏向,直到下一個線程把上一個替換掉!AeC28資訊網——每日最新資訊28at.com

代碼里循環了三次,對象都是一樣的!AeC28資訊網——每日最新資訊28at.com

「節點:在只有一個線程訪問代碼塊的時候,對象中會記錄當前線程id。」AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

「以上都是在一個線程來訪問的情況下」AeC28資訊網——每日最新資訊28at.com

來到序號5,我們新建了一個線程來進行加鎖。此時會判斷當前線程id和新線程id是否一致,不一致就會認為有競爭關系,會立刻切換為輕量級鎖。對象頭序號為:00AeC28資訊網——每日最新資訊28at.com

「節點:當有兩個線程交替獲取鎖時,不存在同時競爭獲取鎖時。」AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

序號6和7一起說,我們讓上面序號5這個線程獲取鎖后睡眠3s,持續獲得鎖。在開啟一個新的線程去競爭獲取鎖,此時先進行自適應CAS自旋,一般10次后一直沒辦法獲取鎖,判定為激烈競爭關系。變為重量級鎖,序號7線程會進行放到阻塞隊列中。對象頭序號為:10。AeC28資訊網——每日最新資訊28at.com

經過睡眠后,序號6在此獲取對象的信息時,已經變為重量級鎖!AeC28資訊網——每日最新資訊28at.com

「節點:有兩個及其以上線程同時獲取鎖,且在自適應自旋范圍內沒有獲取到鎖」。AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

下面是代碼,大家可以在本地試一下!AeC28資訊網——每日最新資訊28at.com

/** * jvm默認延時4s自動開啟偏向鎖, * 可通過 -XX:BiasedLockingStartupDelay=0 * 取消延時如果不要偏向鎖,可通過-XX:-UseBiasedLocking = false * @author wangzhenjun * @date 2023/10/18 14:42 */public class LockUp {    @SneakyThrows    public static void main(String[] args) {        LockInfo lockInfo = new LockInfo();        System.out.println("1.無狀態:" + ClassLayout.parseInstance(lockInfo).toPrintable());        Thread.sleep(6000);        LockInfo lock = new LockInfo();        System.out.println("2.已經開啟了偏向鎖模式:" + ClassLayout.parseInstance(lock).toPrintable());        for (int i = 0; i < 3; i++) {            synchronized (lock) {                System.out.println("3.偏向鎖模式下,加鎖狀態:" + ClassLayout.parseInstance(lock).toPrintable());            }            System.out.println("4.鎖釋放了,加鎖狀態:" + ClassLayout.parseInstance(lock).toPrintable());        }        new Thread(() -> {            synchronized (lock) {                System.out.println("5.輕量級鎖,加鎖狀態:" + ClassLayout.parseInstance(lock).toPrintable());                System.out.println("睡眠3s");                try {                    Thread.sleep(3000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("6.輕量級鎖=>重量級鎖,加鎖狀態:" + ClassLayout.parseInstance(lock).toPrintable());            }        }).start();        Thread.sleep(1000);        new Thread(() -> {            synchronized (lock) {                System.out.println("重量級鎖,加鎖狀態:" + ClassLayout.parseInstance(lock).toPrintable());            }        }).start();    }}

六、總結與拓展

經過實戰,我們知道了每一個的切換條件,可以在面試中好好地回答了。不至于面試官反問一下就不堅定了!AeC28資訊網——每日最新資訊28at.com

關于切換到重量級鎖后,有興趣的話,可以下載openJDK源碼去看一下關于hotspot/src/share/vm/runtime/objectMonitor.cpp和hotspot/src/share/vm/runtime/objectMonitor.hpp。AeC28資訊網——每日最新資訊28at.com

源碼下載地址:https://github.com/openjdk/jdk8AeC28資訊網——每日最新資訊28at.com

objectMonitor.cpp:是 OpenJDK 中實現 Java 同步機制的核心部分,它負責管理對象監視器,確保多線程程序能夠正確協同工作,實現線程同步和等待/通知機制。AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

objectMonitor.hpp:主要用于定義對象監視器的接口和數據結構,為實際的對象監視器的實現提供了基礎。AeC28資訊網——每日最新資訊28at.com

AeC28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-17661-0.html不吃飯也要掌握的Synchronized鎖升級過程

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 一文讀懂Android架構演進歷程

下一篇: 一文帶你了解Spring Actuator

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 台南市| 胶州市| 穆棱市| 日照市| 襄垣县| 汕尾市| 抚顺市| 富源县| 乌恰县| 宁津县| 外汇| 台北市| 南投县| 长顺县| 孝昌县| 聂拉木县| 永年县| 康乐县| 乌审旗| 偃师市| 浦县| 通道| 贺兰县| 宣汉县| 崇仁县| 巴东县| 昌黎县| 新田县| 化州市| 增城市| 登封市| 娄底市| 泸定县| 定陶县| 招远市| 平邑县| 绥德县| 广州市| 施甸县| 保靖县| 阜南县|