成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開發 后端
在JDK1.6之前,Synchronized的性能一直沒有ReentrantLock性能高,主要是因為Synchronized涉及到用戶態和內核態的切換,這個是在操作系統和硬件是非常消耗資源的。經過不斷的統計分析,發現大部分時間一個鎖都是一個線程去獲取,如果只有一個線程來嘗試加鎖,就是重量級鎖,顯而浪費資源。

一、前言

在面試題中經常會有這么一道面試題,談一下synchronized鎖升級過程?

之前背了一些,很多文章也說了,到底怎么什么條件才會觸發升級,一直不太明白。

實踐是檢驗真理的唯一標準,今天就和大家一起實踐一下,什么條件才會升級!

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

在實踐之前,我們先一步步的來了解!為什么要升級呢?

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

經過不斷的統計分析,發現大部分時間一個鎖都是一個線程去獲取,如果只有一個線程來嘗試加鎖,就是重量級鎖,顯而浪費資源。

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

此時,就引入了很多鎖類型,下面我們來具體看看!

三、鎖分類

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

輕量級鎖:當一個或多個線程嘗試獲取同一個鎖時,偏向鎖會升級為輕量級鎖。輕量級鎖采用CAS(Compare and Swap)操作來減小鎖的競爭。采用自適應自旋!

重量級鎖:操作系統的調度器會介入,將競爭鎖的線程掛起,直到鎖被釋放為止,重量級鎖的開銷相對較高。

「補充:」

「自適應自旋的基本思想是根據鎖的爭用情況,決定線程是否應該自旋等待,以及自旋等待的時間,一般情況為自旋10次。」

四、對象內存結構

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

我們本次主要用到對象頭,我們再看一下詳細的對象頭信息里有什么:

五、圖解鎖升級過程

先來一個簡圖:

下面引用百度上的一張詳細一點的圖:

我們來詳細的說一下鎖的升級過程,在每一個鎖切換時的條件是什么?

在JDK8時,偏向鎖默認是在程序啟動后4s自動開啟的,在JKD15之后默認是不開啟的!

可以設置無延遲時間啟動:-XX:BiasedLockingStartupDelay=0也可以不啟動偏向鎖:-XX:-UseBiasedLocking = false。

直接說有點不形象,我們下面結合代碼來實戰,看一下具體情況!

六、實戰鎖升級過程

為了我們能夠查詢對象結構,我們需要引入jar幫助我們查看!

1、導入依賴

「注意」:不要使用高版本的,高版本不顯示2進制,不好觀察!

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

2、實戰代碼和解析

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

此時我們睡眠6s,包裝偏向鎖開啟成功!

我們來到序號2,開啟了偏向鎖,我們發現對象頭序號為:101。

「節點:從無鎖到偏向鎖切換的條件:JDK8中默認4s后開啟,JDK15需要手動開啟」。

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

代碼里循環了三次,對象都是一樣的!

「節點:在只有一個線程訪問代碼塊的時候,對象中會記錄當前線程id。」

「以上都是在一個線程來訪問的情況下」

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

「節點:當有兩個線程交替獲取鎖時,不存在同時競爭獲取鎖時。」

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

經過睡眠后,序號6在此獲取對象的信息時,已經變為重量級鎖!

「節點:有兩個及其以上線程同時獲取鎖,且在自適應自旋范圍內沒有獲取到鎖」。

下面是代碼,大家可以在本地試一下!

/**
 * 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();

    }
}

七、總結與拓展

經過實戰,我們知道了每一個的切換條件,可以在面試中好好地回答了。不至于面試官反問一下就不堅定了!

關于切換到重量級鎖后,有興趣的話,可以下載openJDK源碼去看一下關于hotspot/src/share/vm/runtime/objectMonitor.cpp和hotspot/src/share/vm/runtime/objectMonitor.hpp。

源碼下載地址:https://github.com/openjdk/jdk8

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

objectMonitor.hpp:主要用于定義對象監視器的接口和數據結構,為實際的對象監視器的實現提供了基礎。

責任編輯:姜華 來源: 小王博客基地
相關推薦

2022-03-08 08:44:13

偏向鎖Java內置鎖

2024-06-27 08:55:41

2024-08-13 14:08:25

2021-03-31 10:05:26

偏向鎖輕量級鎖

2021-07-06 13:32:55

JVM

2021-07-01 19:30:23

JVM內部鎖線程

2020-04-06 13:50:43

數據安全大數據5G

2024-04-19 08:05:26

鎖升級Java虛擬機

2022-07-04 08:01:01

鎖優化Java虛擬機

2020-05-07 08:07:57

synchronize線程

2021-12-16 18:38:13

面試Synchronize

2021-08-03 07:40:46

Synchronize鎖膨脹性能

2011-11-28 12:31:20

JavaJVM

2009-09-25 16:43:44

Hibernate悲觀Hibernate樂觀

2009-12-16 10:57:16

Ruby文件鎖

2021-02-07 07:40:31

Synchronize用法

2021-12-14 14:50:12

synchronizeJava

2010-07-26 15:17:46

SQL Server鎖

2010-09-01 15:37:04

DHCP工作過程

2024-10-08 09:10:03

JDK通信并發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美日韩专区 | 日韩字幕 | 日韩一二区在线 | 黄色日本片 | 欧美精品a∨在线观看不卡 欧美日韩中文字幕在线播放 | 欧美h视频 | 欧美一区精品 | 国产伦精品一区二区三区在线 | 91视频一区二区 | 日本在线免费观看 | 羞羞视频在线网站观看 | 九九九精品视频 | 国内精品久久精品 | 成人午夜电影网 | 一区二区三区四区在线视频 | www.国产 | 亚洲欧美激情精品一区二区 | 一本一道久久a久久精品综合蜜臀 | 一区二区三区在线免费观看 | 亚洲精品国产精品国自产在线 | 欧美二三区 | 亚洲国产精品99久久久久久久久 | 精品国产91 | 中文字幕一级 | 国产在线精品一区二区 | 自拍亚洲 | 亚洲黄色高清视频 | 国产欧美在线视频 | 亚洲精品久久久久久首妖 | av在线伊人 | 亚洲精品第一 | 欧美激情欧美激情在线五月 | 亚洲久草 | 久久在线看 | 国产精品久久国产精品 | 国产在线一区二 | 91精品一区二区三区久久久久久 | 日本精品视频在线观看 | 亚洲a在线视频 | 亚洲一一在线 | 久久久99国产精品免费 |