国产精品chinese,色综合天天综合精品网国产在线,成午夜免费视频在线观看,清纯女学生被强行糟蹋小说

    <td id="ojr13"><tr id="ojr13"><label id="ojr13"></label></tr></td>
        • <source id="ojr13"></source>
            <td id="ojr13"><ins id="ojr13"><label id="ojr13"></label></ins></td>

            Article / 文章中心

            Monitor系列問題問答

            發(fā)布時間:2021-12-13 點擊數(shù):694

            1、簡介


            2、對象頭


            3、Mark Word


            4、Monitor


            5、monitorente && monitorexit


            1、簡介

            我們Java程序員編碼時談論的最多的兩個字就是對象,Java中幾乎所有的技術都是圍繞對象展開。本文將要講述的Monitor并不是Java對象,而是在操作系統(tǒng)中關聯(lián)的“對象”,Monitor是Java重量級鎖synchronized實現(xiàn)的關鍵,因此學習Java單機同步機制就離不開對Monitor的剖析。Monitor經(jīng)常被人們稱為監(jiān)視器鎖和管程。


            2、對象頭

            Monitor與Java對象頭相關聯(lián),因此剖析Monitor之前必須了解Java對象的組成結構。Java對象在內存中由三部分組成,分別是對象頭、實例數(shù)據(jù)、對齊填充。以32位虛擬機為例(64位不同),對象頭(Header)占8個字節(jié)共64位(數(shù)組對象頭與普通對象頭不同,數(shù)組對象頭12個字節(jié)共96位);實例數(shù)據(jù)(Instance Data)存儲這對象的實際數(shù)據(jù),因此大小與實際數(shù)據(jù)大小一致;對齊填充(Padding)是可選項,用于將內存對齊為8字節(jié)的整數(shù)倍。


            普通對象內存組成image.png如上兩張圖展示了Java對象內存結構,本文說的Monitor和這個有啥關系呢?其實對象頭(Header)中的Mark Word就是用來存放Monitor對象的指針的,在一開始小捌就說了Monitor并不是Java對象,而是在操作系統(tǒng)中關聯(lián)的“對象”,因此Java對象如果想要和Monitor進行關聯(lián),就必須在Java對象中記錄Monitor的內存地址,這樣才能通過Java對象找到這個Monitor嘛!


            注:Klass Word存放的是指向對象對應的Class對象的指針。


            3、Mark Word

            可想而知,想要深入探討Monitor肯定避不開Mark Word,這個時候暴躁的程序員小哥肯定不爽了,你特么不是說Mark Word中存放的Monitor的內存地址么,我知道了啊……

            別急,并不是想的那樣的,這里稍微有一丟丟復雜,聽我慢慢道來。

            Java對象在不同的狀態(tài)下,Mark Word存儲的值完全不同,尤其是在JDK1.6對鎖優(yōu)化之后,Mark Word這32bits內存空間,真的是被Java大師們壓榨到了極致。了解這個需要有一定的JVM和synchronized知識,如果不懂的話也無所謂,先了解就好,后面我們一起學習synchronized鎖升級過程。


            初始狀態(tài)下Java對象頭的Mark Word里默認存儲的是對象的hashcode、GC分代年齡、是否偏向鎖和鎖標志位

            image.png4、Monitor

            上面鋪墊了這么多東西,其實就是為了講述Monitor和Java對象頭中Mark Word的關系,可以看出來只有在重量級鎖的情況下Java對象頭中Mark Word才會關聯(lián)一個Monitor對象,那么Monitor又是個什么東西呢?我相信你一定很好奇吧!


            Monitor內部分由三部分組成分別是Owner、EntryList、WaitSet;


            Owner用于記錄當前Monitor的所屬線程

            EntryList是一個鏈表結構,用于記錄阻塞在當前鎖對象上的線程

            WaitSet用于記錄獲取鎖之后進入Waiting狀態(tài)的線程image.png當對象獲取到鎖之后,由于某些資源并未準備完成,需要等待其他線程去準備資源,此時線程會通過wait()/notify()等方法進入等待/通知模式,在這種情況下線程釋放鎖之后會進入WaitSet,當其他線程準備好資源之后會通知WaitSet中等待的線程,WaitSet中的線程會進入到EntryList中,重新參與鎖競爭。

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

            版權聲明:本文為CSDN博主「李子捌」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權協(xié)議,轉載請附上原文出處鏈接及本聲明。

            原文鏈接:https://blog.csdn.net/qq_41125219/article/details/121687007image.png5、monitorente && monitorexit

            知道了Monitor是什么,也知道了Java對象與Monitor之間的關系,但是還有一層疑問;程序在運行過程中是如何知道要給Java對象去關聯(lián)一個Monitor呢?

            這就需要一點點Java字節(jié)碼相關的知識了,Java的源代碼在編譯器編譯之后生成的Class文件中存儲的是字節(jié)碼指令,程序執(zhí)行本質上是一條條指令按照既定順序的流水線工作,那這只有一種可能了,編譯器在編譯成Java字節(jié)碼時做了記號,這個記號就是monitorente /monitorexit。


            我們先來看一段簡單的synchronized代碼塊:

            image.pngimage.pngimage.png

             0 getstatic #2 <com/lzb/concurrency/demo2/MonitorDemo.LOCK : Ljava/lang/Object;>  3 dup  4 astore_1  5 monitorenter  6 getstatic #3 <com/lzb/concurrency/demo2/MonitorDemo.count : I>  9 iconst_1 10 iadd 11 putstatic #3 <com/lzb/concurrency/demo2/MonitorDemo.count : I> 14 aload_1 15 monitorexit 16 goto 24 (+8) 19 astore_2 20 aload_1 21 monitorexit 22 aload_2 23 athrow 24 return

            前三行字節(jié)碼分別表示:

            • getstatic 獲取靜態(tài)鎖對象LOCK
            • dup 復制一份LOCK對象的引用,用于鎖退出
            • astore_1 復制的引用存入臨時變量1中 3 dup reference -> slot 1image.pngsynchronized臨界區(qū)七行字節(jié)碼分別表示:


            monitorenter 關聯(lián)一個操作系統(tǒng)Monitor對象,替換LOCK對象的Mark Word為Monitor地址

            getstatic 獲取靜態(tài)變量count

            iadd count++操作

            putstatic 賦值++操作后的count

            aload_1 獲取LOCK對象的引用,上面dup復制后astore_1 指令存儲的那份地址

            monitorexit 還原Mark Word,將Monitor對象指針替換為monitorenter 加鎖時保存在Monitor對象中的數(shù)據(jù),如hashcode、分代年齡等數(shù)據(jù);同時喚醒等待在EntryList中阻塞等待的線程。image.png異常表中有兩行記錄:


            第一行表示:6 -> 16行字節(jié)碼中發(fā)生了異常,會跳轉到19行,這就是synchronized加鎖的代碼區(qū)域,如果加鎖中出現(xiàn)異常,JVM會處理異常,正確釋放鎖

            第二行表示:19 -> 22行字節(jié)碼中發(fā)生了異常,會跳轉到19行,

            未發(fā)生異常情況:


            goto 24 (+8) 沒有產生異常,直接執(zhí)行24行指令

            return 方法運行結束image.png發(fā)生異常情況:


            astore_2 將異常對象存儲到臨時變量中 e -> slot 2

            aload_1 加載LOCK鎖對象引用地址

            monitorexit 還原Mark Word,將Monitor對象指針替換為monitorenter 加鎖時保存在Monitor對象中的數(shù)據(jù),如hashcode、分代年齡等數(shù)據(jù);同時喚醒等待在EntryList中阻塞等待的線程。

            aload_2 加載異常對象

            athrow 拋出異常對象

            return 方法運行結束image.png


            image.png


            image.png


            image.png