国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

java鎖優(yōu)化策略

warkiz / 2762人閱讀

摘要:前置知識點對象頭要了解鎖優(yōu)化策略中的輕量級鎖與偏向鎖的原理和運作過程,需要先了解虛擬機的對象頭部分的內(nèi)存布局。否則說明這個鎖對象已經(jīng)被其他線程搶占了。

前置知識點:對象頭

要了解鎖優(yōu)化策略中的輕量級鎖與偏向鎖的原理和運作過程,需要先了解Hotspot虛擬機的對象頭部分的內(nèi)存布局。

對象頭(摘自《深入理解java虛擬機》)

對象頭信息是與對象自身定義的數(shù)據(jù)無關(guān)的額外存儲成本

如果對象是數(shù)組類型,則虛擬機用3個Word(字寬,在32位虛擬機中,一字寬等于四字節(jié),即32bit)存儲對象頭。如果對象是非數(shù)組類型,則用2Word存儲對象頭。一個額外的字寬用于存儲數(shù)組長度。

第一個字寬,用來存儲對象自身的運行時數(shù)據(jù) 如:哈希嗎(HashCode)、GC分代年齡(Generational GC Age)等,這部分數(shù)據(jù)的長度在32位和64位的虛擬機中分別為32bit和64bit,簡稱“Mark Word”。

第二個字寬用于存儲指向方法區(qū)對象類型數(shù)據(jù)的指針。

對象頭信息會根據(jù)對象的狀態(tài)復(fù)用自己的存儲空間。例如:在32位的HotSpot虛擬機中對象未被鎖定的狀態(tài)下,Mark Word的32bit空間中的25bit用于存儲對象哈希嗎(HashCode),4bit用于存儲對象分代年齡,2bit用于存儲鎖標(biāo)志位,1bit固定為0。

整個對象頭如下圖:第三行即為第三部分,非數(shù)組類型的沒有第三個字寬。

Mark Word的默認存儲結(jié)構(gòu)如下圖:

在運行期間Mark Word里存儲的數(shù)據(jù)會隨著鎖標(biāo)志位的變化而變化。Mark Word可能變化為存儲以下4種數(shù)據(jù):

在64位虛擬機下,Mark Word是64bit大小的,其存儲結(jié)構(gòu)如下:

鎖狀態(tài)

Java SE1.6為了減少獲得鎖和釋放鎖所帶來的性能消耗,引入了“偏向鎖”和“輕量級鎖”,

所以在Java SE1.6里鎖一共有四種狀態(tài),無鎖狀態(tài),偏向鎖狀態(tài),輕量級鎖狀態(tài)和重量級鎖狀態(tài),它會隨著競爭情況逐漸升級。

鎖可以升級但不能降級,意味著偏向鎖升級成輕量級鎖后不能降級成偏向鎖。

這種鎖升級卻不能降級的策略,目的是為了提高獲得鎖和釋放鎖的效率,下文會詳細分析。

偏向鎖

Hotspot的作者經(jīng)過以往的研究發(fā)現(xiàn)大多數(shù)情況下鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得,為了讓線程獲得鎖的代價更低而引入了偏向鎖。

在沒有實際競爭的情況下,還能夠針對部分場景繼續(xù)優(yōu)化。如果不僅僅沒有實際競爭,自始至終,使用鎖的線程都只有一個,那么,維護輕量級鎖都是浪費的。偏向鎖的目標(biāo)是,減少無競爭且只有一個線程使用鎖的情況下,使用輕量級鎖產(chǎn)生的性能消耗。輕量級鎖每次申請、釋放鎖都至少需要一次CAS,但偏向鎖只有初始化時需要一次CAS。

配置

默認-XX:+UseBiasedLocking=true
-XX:-UseBiasedLocking=false關(guān)閉偏向鎖
應(yīng)用程序啟動幾秒鐘之后才激活
-XX:BiasedLockingStartupDelay = 0關(guān)閉延遲

加鎖流程

獲取偏向鎖

根據(jù)上圖,我們可以看到,首先判斷鎖對象是不是可偏向?qū)ο螅?strong>若鎖對象已經(jīng)被輕量級鎖定或者重量級鎖定了,因為鎖不會降級,所以它是不可偏向,同樣的,關(guān)閉了偏向鎖的設(shè)置-UseBiasedLocking=false,也會造成鎖對象不可偏向)

接下來,我們假定鎖對象處于可偏向狀態(tài),并且ThreadID為0即biasable & unbiased狀態(tài)(這里不討論epoch和age)

當(dāng)一個線程試圖鎖住一個處于biasable & unbiased狀態(tài)的對象時,通過一個CAS將自己的ThreadID放置到Mark Word中相應(yīng)的位置,如果CAS操作成功進入第(3)步否則進入(4)步

當(dāng)進入到這一步時代表當(dāng)前沒有鎖競爭,鎖對象繼續(xù)保持biasable可偏向狀態(tài),但是這時ThreadID字段被設(shè)置成了偏向鎖所有者的ID,然后進入到第(6)步

當(dāng)前線程執(zhí)行CAS獲取偏向鎖失敗(這一步是偏向鎖的關(guān)鍵),表示在該鎖對象上存在競爭并且這個時候另外一個線程在持有偏向鎖所有權(quán)。這個時候,就要判斷持有偏向鎖的線程是否還活著,因為一個線程執(zhí)行完同步代碼塊后,不會主動釋放偏向鎖。如果持有偏向鎖的線程還活著,將偏向鎖消除,膨脹為輕量級鎖,否則,將偏向鎖消除,讓爭鎖的線程持有偏向鎖。
具體過程是:當(dāng)?shù)竭_全局安全點(safepoint,在這個時間點上沒有字節(jié)碼正在執(zhí)行)時擁有偏向鎖的線程被掛起,然后檢查持有偏向鎖的線程是否活著,如果線程不處于活動狀態(tài),則將對象頭設(shè)置成無鎖狀態(tài),如果線程仍然活著,鎖對象有可能升級為輕量級鎖狀態(tài)(鎖標(biāo)志位置為00),阻塞在安全點的原持有線程被釋放,進入到輕量級鎖的執(zhí)行路徑中,繼續(xù)往下執(zhí)行同步代碼。

當(dāng)一個線程試圖鎖住一個處于biasable & biased并且ThreadID不等于自己的ID時,這時由于存在鎖競爭必須進入到第(4)步來撤銷偏向鎖。

運行同步代碼塊

輕量級鎖

輕量級鎖是由偏向所升級來的,偏向鎖運行在一個線程進入同步塊的情況下,當(dāng)?shù)诙€線程加入鎖爭用的時候,偏向鎖就會升級為輕量級鎖;

加鎖過程

在代碼進入同步塊的時候,如果此同步對象沒有被鎖定(鎖標(biāo)志位為“01”狀態(tài)),虛擬機首先將在當(dāng)前線程的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用于存儲鎖記錄目前的Mark Word的拷貝(稱為Displaced Mark Word)以及記錄鎖對象的指針owner。

當(dāng)一個線程來獲取這個鎖,虛擬機將使用CAS操作嘗試將鎖對象的Mark Word更新為指向Lock Record的指針。如果這個更新動作成功了,那么這個線程就擁有了該對象的鎖,并且對象Mark Word的鎖標(biāo)志位(Mark Word的最后2bit)將轉(zhuǎn)變?yōu)椤?0”,即表示此對象處于輕量級鎖定狀態(tài),這時候線程堆棧與對象頭的狀態(tài)如下:

如果這個更新操作失敗了,虛擬機首先會檢查對象的Mark Word是否指向當(dāng)前線程的棧幀。如果指向,說明當(dāng)前線程已經(jīng)擁有了這個對象的鎖,那就可以直接進入同步塊繼續(xù)執(zhí)行。
否則說明這個鎖對象已經(jīng)被其他線程搶占了。那么它就會自旋等待鎖,一定次數(shù)后仍未獲得鎖對象,則修改mark word,將其修改為重量級鎖的指針,表示該鎖對象進入了重量鎖狀態(tài)。如果有兩條以上的線程爭用同一個鎖,那輕量級鎖就不再有效,要膨脹為重量級鎖,鎖標(biāo)志的狀態(tài)值變?yōu)椤?0”,Mark Word中存儲的就是指向重量級(互斥量)的指針。

由輕量鎖切換到重量鎖,是發(fā)生在輕量鎖釋放鎖的期間的,另一邊,持有輕量級鎖的線程,之前在獲取鎖的時候它拷貝了鎖對象頭的mark word,在釋放鎖的時候如果它發(fā)現(xiàn)在它持有鎖的期間有其他線程來嘗試獲取鎖了,并且該線程對mark word做了修改,兩者比對發(fā)現(xiàn)不一致導(dǎo)致釋放鎖的CAS失敗,于是也切換到重量鎖,釋放輕量鎖,并喚醒阻塞的線程。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/71559.html

相關(guān)文章

  • 淺談Java的實現(xiàn)和優(yōu)化

    摘要:這兩種策略的區(qū)別就在于,公平策略會讓等待時間長的線程優(yōu)先執(zhí)行,非公平策略則是等待時間長的線程不一定會執(zhí)行,存在一個搶占資源的問題。 之前有一篇文章我們簡單的談到了Java中同步的問題,但是可能在平常的開發(fā)中,有些理論甚至是某些方式是用不到的,但是從程序的角度看,這些理論思想我們可以運用到我們的開發(fā)中,比如是不是應(yīng)該一談到同步問題,就應(yīng)該想到用synchronized?,什么時候應(yīng)該用R...

    DevWiki 評論0 收藏0
  • Java多線程進階(十)—— J.U.C之locks框架:基于AQS的讀寫(5)

    摘要:關(guān)于,最后有兩點規(guī)律需要注意當(dāng)?shù)牡却犃嘘犑捉Y(jié)點是共享結(jié)點,說明當(dāng)前寫鎖被占用,當(dāng)寫鎖釋放時,會以傳播的方式喚醒頭結(jié)點之后緊鄰的各個共享結(jié)點。當(dāng)?shù)牡却犃嘘犑捉Y(jié)點是獨占結(jié)點,說明當(dāng)前讀鎖被使用,當(dāng)讀鎖釋放歸零后,會喚醒隊首的獨占結(jié)點。 showImg(https://segmentfault.com/img/remote/1460000016012293); 本文首發(fā)于一世流云的專欄:...

    dunizb 評論0 收藏0
  • Java 虛擬機對優(yōu)化所做的努力

    摘要:自選鎖鎖膨脹后,虛擬機為了避免線程真實地在操作系統(tǒng)層面掛起,虛擬機還會在做最后的努力自選鎖。 showImg(https://segmentfault.com/img/remote/1460000016159660?w=500&h=333); 作為一款公用平臺,JDK 本身也為并發(fā)程序的性能絞盡腦汁,在 JDK 內(nèi)部也想盡一切辦法提供并發(fā)時的系統(tǒng)吞吐量。這里,我將向大家簡單介紹幾種 J...

    ralap 評論0 收藏0
  • Java并發(fā)總結(jié)

    摘要:限期阻塞調(diào)用方法等待時間結(jié)束或線程執(zhí)行完畢。終止?fàn)顟B(tài)線程執(zhí)行完畢或出現(xiàn)異常退了。和都會檢查線程何時中斷,并且在發(fā)現(xiàn)中斷時提前放回。工廠方法將線程池的最大大小設(shè)置為,而將基本大小設(shè)置為,并將超時大小設(shè)置為分鐘。 wait()、notify()、notifyAll() Object是所有類的基類,它有5個方法組成了等待、通知機制的核心:notify()、notifyAll()、wait()...

    szysky 評論0 收藏0
  • 史上最全阿里 Java 面試題總結(jié)

    摘要:以下為大家整理了阿里巴巴史上最全的面試題,涉及大量面試知識點和相關(guān)試題。的內(nèi)存結(jié)構(gòu),和比例。多線程多線程的幾種實現(xiàn)方式,什么是線程安全。點擊這里有一套答案版的多線程試題。線上系統(tǒng)突然變得異常緩慢,你如何查找問題。 以下為大家整理了阿里巴巴史上最全的 Java 面試題,涉及大量 Java 面試知識點和相關(guān)試題。 JAVA基礎(chǔ) JAVA中的幾種基本數(shù)據(jù)類型是什么,各自占用多少字節(jié)。 S...

    winterdawn 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<