1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        synchronized關(guān)鍵字的原理刨析

        共 3983字,需瀏覽 8分鐘

         ·

        2020-07-28 17:29

        點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

        優(yōu)質(zhì)文章,第一時間送達(dá)


        66套java從入門到精通實(shí)戰(zhàn)課程分享


        前言

        關(guān)于synchronized原理解析,我們首先要分析一下對象都有哪些東西,對象頭到底存儲了什么,synchronzied關(guān)鍵字到底是如何進(jìn)行鎖膨脹的,在使用過程中同步方法塊和同步代碼塊到底有什么區(qū)別,在回頭看synchronized的使用。針對的時JDK1.6之后的版本的synchronized深度分析。


        前期準(zhǔn)備

        為輸出對象頭導(dǎo)入jar


        <dependency>
        ????<groupId>org.openjdk.jolgroupId>
        ????<artifactId>jol-coreartifactId>
        ????<version>0.11version>
        dependency>


        設(shè)置偏向鎖的啟動延遲


        #關(guān)閉偏向鎖(為什么要關(guān)閉偏向鎖,有什么好處嘛,這個問題先不做回答)
        -XX:-UseBiasedLocking
        #設(shè)置偏向鎖的一個啟動延遲
        -XX:BiasedLockingStartupDelay=0

        對象

        對象中有哪些部分

        新建一個對象,進(jìn)行main方法輸出


        public?class?A?{
        ???int?status=0;
        ???boolean?flag=true;
        }


        public?static?void?main(String[] args) {
        ????a=new?A(); System.out.println(ClassLayout.parseInstance(a).toPrintable());
        }


        輸出的一個對象信息(當(dāng)前的操作系統(tǒng)是一個64位的,32位的是不一樣的)


        從這個上面看,我們可以分析出包含96bit(12byte*8)的對象頭和兩個屬性(status,flag)字段屬性。這些都屬于對象數(shù)據(jù),int 類型的數(shù)據(jù)我們知道,占用4個byte,1個boolean值得可以使用1個byte去表示,那么為什么后面還出現(xiàn)了7個byte,這是因?yàn)閖vm在分配內(nèi)存的時候只能是8的一個倍數(shù)。所以就出現(xiàn)了7個byte。


        所以我們小小的總結(jié)一下。


        一個對象中包含對象頭,實(shí)列數(shù)據(jù),對象填充.


        對象頭有哪些東西

        通過文檔查找來驗(yàn)證


        jvm底層一個是基于C/C++來實(shí)現(xiàn)的,查看版本java -version 可以知道jvm的實(shí)現(xiàn)是HotSport來實(shí)現(xiàn)的jvm規(guī)范和標(biāo)準(zhǔn)的。通過openjdk的官方文檔 [https://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html]查看對于對象頭的一個定義。

        說了一下包含兩部分,mark word 和 klass pointer(這個對象對應(yīng)的class類指針地址) 兩部分。在open Jdk的源碼中有一個markOop的文件中說明了在64bit的操作系統(tǒng)中,mark word 占用了64位的。所以我們得出一個結(jié)論。


        那么此時我們知道了,對象頭中包含了 這個對象對應(yīng)的class類的類型,Gc age,hashcode , synchronized關(guān)鍵字的同步狀態(tài)。


        對象頭再深入分析


        這里的klass word 為什么是32bit呢,因?yàn)樵趈vm中如果開啟了指針壓縮(1.8默認(rèn)開啟的)就會對對象頭進(jìn)行壓縮。所以看到是32bit,如果關(guān)閉就會看到是64bit。

        關(guān)閉指針壓縮


        -XX:-UseCompressedOops

        鎖的一個狀態(tài)分析

        new 對象A


        public?static?void?main(String[] args) {
        ???a=new?A();
        ???System.out.println(ClassLayout.parseInstance(a).toPrintable());
        ???a.hashCode();
        ???System.out.println(ClassLayout.parseInstance(a).toPrintable());
        }

        第一次打印這個對象A的情況(沒有計(jì)算a的hashcode)無鎖可偏向,就是沒有線程來獲取這把鎖,也沒有計(jì)算hashcode。

        全部為0的就是沒有HashCode 或者 線程ID 是空的。


        第二次打印這個對象A的情況(計(jì)算了a的hashcode),無鎖不可偏向,沒有線程來獲取這把鎖,但是計(jì)算了hashcode。


        并設(shè)置了HashCode 到mark word 中。

        當(dāng)我們的代碼變成這樣下面這樣時,我們在看這個對象頭的中mark word 的一個鎖的狀態(tài)。


        public?static?void?main(String[] args) {
        ???a=new?A();
        ???System.out.println(ClassLayout.parseInstance(a).toPrintable());
        ???a.hashCode();
        ???System.out.println(ClassLayout.parseInstance(a).toPrintable());
        ???lock();

        ???new?Thread(()->{
        ??????lock();
        ???}).start();
        }

        public??static??void??lock(){
        ???synchronized (a){
        ??????System.out.println("線程名稱=="+Thread.currentThread().getName());
        ??????System.out.println(ClassLayout.parseInstance(a).toPrintable());
        ???}
        }


        main線程來進(jìn)行加鎖操作,main線程第一次來加鎖,直接變成了輕量級鎖,這是為什么呢,不應(yīng)該是偏向鎖嘛。


        這是因?yàn)椋簩@個對象A進(jìn)行了一個hashcode計(jì)算,那么hashcode占據(jù)了56個bit,鎖的一個狀態(tài)就變成了無鎖,不可偏向狀態(tài)。沒有辦法進(jìn)行偏向,第一個線程來獲取鎖的時候就會變成輕量級鎖。


        此時我們把計(jì)算hashcode注釋掉


        public?static?void?main(String[] args) {
        ???a=new?A();
        ???System.out.println(ClassLayout.parseInstance(a).toPrintable());
        ?
        ???lock();

        ???new?Thread(()->{
        ??????lock();
        ???}).start();
        }

        public??static??void??lock(){
        ???synchronized (a){
        ??????System.out.println("線程名稱=="+Thread.currentThread().getName());
        ??????System.out.println(ClassLayout.parseInstance(a).toPrintable());
        ???}
        }
        ————————————————
        版權(quán)聲明:本文為CSDN博主「只穿T恤的程序員」的原創(chuàng)文章,遵循CC 4.0?BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
        原文鏈接:https://blog.csdn.net/weixin_36114346/article/details/107488920


        運(yùn)行代碼得到一個 main線程加鎖之后,對象頭中的鎖的一個狀態(tài)變成了無鎖 可偏向,但是多了一個線程ID。

        線程Thread-0運(yùn)行的一個情況,此時線程Thread-0變成了輕量級鎖,線程ID為thread-0,發(fā)生了一個鎖的膨脹。


        但是先需要撤銷偏向鎖,再把鎖的狀態(tài)變成輕量級鎖,而輕量級鎖是一個CAS操作。相對撤銷偏向鎖來說來消耗的性能要低的多。

        當(dāng)再執(zhí)行一個線程Thread-1時,此時就變成了重量級鎖。從輕量級鎖變成了重量級鎖。

        到這里我們分析完了一個鎖的狀態(tài),包括鎖膨脹情況。


        畫圖總結(jié)鎖的一個膨脹

        沒有進(jìn)行HashCode運(yùn)算的流程


        進(jìn)行過HashCode運(yùn)算的流程


        基本使用

        synchronzied加鎖的對象為A,叫對象鎖 ,修飾的是代碼塊,進(jìn)入同步代碼塊之前要獲取鎖。


        public??static??void??lock(){
        ???synchronized (a){
        ??????System.out.println("線程名稱=="+Thread.currentThread().getName());
        ??????System.out.println(ClassLayout.parseInstance(a).toPrintable());
        ???}
        }


        synchronzied在靜態(tài)方法上加鎖,加鎖的類型是這個方法對應(yīng)的類鎖。進(jìn)入同步方法之前要獲取鎖。


        public???static????synchronized??void??lock2(){
        }


        synchronzied在實(shí)列方法上加鎖,加鎖的類型是這個方法對應(yīng)的對象實(shí)列鎖。進(jìn)入同步方法之前要當(dāng)前對象實(shí)列鎖。


        public?????synchronized??void??lock2(){
        }


        ————————————————

        版權(quán)聲明:本文為CSDN博主「只穿T恤的程序員」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。

        原文鏈接:

        https://blog.csdn.net/weixin_36114346/article/details/107488920


        ??? ?




        感謝點(diǎn)贊支持下哈?


        瀏覽 47
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            东京热欧美 | 中文字幕日韩精品人妻 | 午夜影院在线 | 色婷婷五月天在线视频 | 波霸巨大乳一区二区三区 | 大香蕉五月丁香 | 超碰97干 | 亚洲日韩精品秘 在线观看 | 国产综合在线视频 | 涩999 |