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

資訊專欄INFORMATION COLUMN

偏向鎖狀態轉移原理

alaege / 1179人閱讀

摘要:此時偏向擁有者會像輕量級鎖操作那樣,它的堆棧會填入鎖記錄,然后對象本身的會被更新成指向棧上最老的鎖記錄,然后線程本身在安全點的阻塞會被釋放如果沒有被原有的偏向鎖持有者持有,會撤銷對象重新回到可偏向但是還沒有偏向的狀態,然后嘗試重新獲取鎖。

為什么需要偏向鎖

當多個處理器同時處理的時候,通常需要處理互斥的問題。
一般的解決方式都會包含acquirerelease這個兩種操作,操作保證,一個線程在acquire執行之后,在它執行release之前,其它線程不能完成acquire操作。這個過程經常就涉及到鎖。研究表明(L. Lamport A fast mutual execlusion algorithm),通過 fast locks算法可以做到,lock和unlock操作所需的時間與潛在的競爭處理器數無關。
java內置了monitor來處理多線程競爭的情況.

一種優化方式是使用 輕量鎖來在大多數情況下避免重量鎖的使用,輕量鎖的主要機制是在monitor entry的時候使用原子操作,某些退出操作也是這樣,如果有競爭發生就轉而退避到使用操作系統的互斥量

輕量鎖認為大多數情況下都不會產生競爭

在鎖的使用中一般會使用幾種原子指令:
- CAS:檢查給定指針位置的值和傳入的值是否一致,如果一致,就修改
- SWAP:替換指針原位置的值,并返回舊的值
- membar:內存屏障約束了處理器在處理指令時的重排序情況,比如禁止同讀操作被重排序到寫操作之后

Java中使用 two-word 對象頭
1. 是 mark word,它包括同步信息,垃圾回收信息、hash code信息
2. 指向對象的指針對象

這些指令的花銷很昂貴,因為他們的實現通常會耗盡處理器的重排序緩沖區,從而限制了處理器原本能夠像流水線一樣處理指令的能力。研究數據發現(Eliminating_synchronization-related_atomic_operations_with_biased_locking_and_bulk_rebiasing)原子操作在真實的應用中,比如javac ,會導致性能下降20%。

> [此處2006年的文章第4段](https://blogs.oracle.com/dave/biased-locking-in-hotspot)大概說CAS和fence在操作系統中是序列化處理的,而序列化指令會使CPU幾乎停止,終止并禁止任何無需指令,并等待本地存儲耗盡。在多核處理器上,這種處理會導致相當大的性能損失

另一種優化的方式是使用偏向鎖,它不僅認為大多數情況下是沒有競爭的,而且在整個的monitor的一生中,都只會有一個線程來執行enter和exit,這樣的監視器就很適合偏向于這個線程了。當然如果這時有另外一個線程嘗試進入偏向鎖,即使沒有發生競爭,也需要執行 偏向鎖撤銷操作

輕量鎖

當輕量鎖通過monitorenter指令獲取鎖的時候,鎖記錄肯定會被記錄到線程的棧里面去,以表示鎖獲取操作。鎖記錄會持有原始對象的mark word和一些必備的元數據來識別鎖住的對象。在獲取鎖的時候,mark word會被拷貝一份到鎖記錄(這個操作稱為 displaced mark word)然后執行CAS操作嘗試是的對象的mark word指針指向鎖記錄。如果CAS成功,當前線程就持有了鎖,如果失敗,其它線程獲取鎖,這是鎖就“膨脹”,轉而使用了操作系統的互斥量和條件,在“膨脹”的過程中,對象本身的mark word會經過CAS操作指向含有mutex和condition的數據結構。

當執行unlock的時候,扔通過CAS來操作mark word,如果CAS成功了,說明沒有競爭,同時維持輕量鎖;如果失敗了,鎖就處于競爭態,當被持有時,會以一種“非常慢”的方式來正確的釋放鎖并通知其他等待線程來獲取鎖

同一個線程重新處理的方式很直白,在輕量鎖發現要獲取的鎖已經被當前線程持有的時候,它會存一個0進去,而不對mark word做任何處理,同樣在unlock的時候,如果有看到0,也不會更新對象的mark word.并每次重入,都會明確的記錄count。

偏向鎖的實現

線程指針是NULL(0)表示當前沒有線程被偏向這個對象

當分配一個對象并且這個對象能夠執行偏向的時候并且還沒有偏向時,會執行CAS是的當前線程ID放入到mark word的線程ID區域。

如果成功,對象本身就會被偏向到當前線程,當前線程會成為偏向所有者

線程ID直接指向JVM內部表示的線程;java虛擬機中則是在最后3bit填充0x5表示偏向模式。

如果CAS失敗了,即另一個線程已經成為偏向的所有者,這意味著這個線程的偏向必須撤銷。對象的狀態會變成輕量鎖的模式,為了達到這一點,嘗試把對象偏向于自己的線程必須能夠操作偏向所有者的棧,為此需要全局安全點已經觸達(沒有線程在執行字節碼)。此時偏向擁有者會像輕量級鎖操作那樣,它的堆棧會填入鎖記錄,然后對象本身的mark word會被更新成指向棧上最老的鎖記錄,然后線程本身在安全點的阻塞會被釋放

如果沒有被原有的偏向鎖持有者持有,會撤銷對象重新回到可偏向但是還沒有偏向的狀態,然后嘗試重新獲取鎖。如果對象當前鎖住了是進入輕量鎖,如果沒有鎖住是進入未被鎖定的,不可偏向對象

下一個獲取鎖的操作會與檢測對象的mark word,如果對象是可偏向的,并且偏向的所有者是當前那線程,會沒有任何額外操作而立馬獲取鎖。

這個時候偏向鎖的持有者的棧不會初始化鎖記錄,因為對象偏向的時候,是永遠不會檢驗鎖記錄的

unlock的時候,會測試mark word的狀態,看是否仍然有偏向模式。如果有,就不會再做其它的測試,甚至不需要管線程ID是不是當前線程ID

這里通過解釋器的保證monitorexit操作只會在當前線程執行,所以這也是一個不需要檢查的理由
不適用偏向鎖的模式

生產生-消費者模式,會有過個線程參與競爭;

一個線程分配多個對象,然后給每個對象執行初始的同步操作,再有其它線程來處理子流程

批量回到可偏向狀態還是撤銷可偏向?

經驗發現為特定的數據結構選擇性的禁用偏向鎖(Store-fremm biased lock SFBL)來避免不合適的情況是合理的。為此需要考慮每個數據結構到底是執行撤銷偏向的消耗小還是重新回到可偏向的狀態消耗下。一種啟發式的方式來決定到底是執行那種方式,在每個類的元數據里面都會包含一個counter和時間戳,每次偏向鎖的實例執行一次偏向撤銷,都會自增,時間戳用于記錄上次執行bulk rebias的時間。

撤銷計數并統計那些處于可偏向但是未偏向狀態的撤銷,這些操作的撤銷只需要一次CAS就可以

counter本身有兩個閾值,一個是bulk rebias閾值,一個是bulk revocation。剛開始的時候,這種啟發式的算法可以多帶帶的決定執行rebias還是revoke,一單bulk rebias的閾值達到,就會執行bulk rebias,轉移到 rebiasable狀態
time閾值用來重置撤銷的計數counter,如果自從上次執行bulk bias已經超過了這個閾值時間,就會發生counter的重置。

這意味著從上次執行bulk rebias到現在并沒有執行多次的撤銷操作,也就是說執行bias仍然是個不錯的選擇

但是如果在執行了bulk rebias之后,在時間閾值之內,仍然一直有撤銷數量增長,一旦達到了bulk revocation的閾值,就會執行bulk revocation,此時這個類的對象不會再被允許使用偏向鎖。

Hotspot中的閾值如下 Bulk rebias threshold 20 Bulk revoke threshold 40 Decay time 25s

撤銷偏向本身是一個消耗很大的事情,因為它必須掛起線程,遍歷棧找到并修改lock records(鎖記錄)

最明顯的查找某個數據結構的所有對象實例的方式就是遍歷堆,這種方式在堆比較小的時候還可以,但是堆變大就顯得性能不好。為類解決這個為題,使用 epoch
epoch是一個時間戳,用來表明偏向的合法性,只要這個數據接口是可偏向的,那么就會在mark word上有一個對應的epoch bit位

這個時候,一個對象被認為已經偏向了線程T必須滿足兩個條件,1: mark word中偏向所有這的標記必須是這個線程,2:實例的epoch必須是和數據結構的epoch相等
epoch本身的大小是限制的,也就是有可能出現循環,但這并不影響方案的正確性

通過這種方式,類C的bulk rebiasing操作會少去很多的花銷。具體操作如下

增大類C的epoch,它本身是一個固定長度的integer,和對象頭中的epoch擁有一樣的bit位數

掃描所有的線程棧來定位當前類C的實例中已經鎖住的,更新他們的epoch為類C的新的epoch或者是,根據啟發式策略撤銷偏向

這樣就不用掃描堆了,對于那些沒有被改變epoch的實例(和類的epoch不同),會被自動當做可偏向但是還沒有偏向的狀態

這種狀態可看做 rebiaseable

膨脹與偏向源碼

當前HotSpot虛擬機的實現

批量撤銷本身存在著性能問題,一般的解決方式如下

添加epoch,如前所訴

線程第一次獲取的時候不偏向,而是在執行一定數量后都有同一個線程獲取再偏向

允許鎖具有永遠改變(或者很少)的固定偏向線程,并且允許非偏向線程獲取鎖而不是撤銷鎖。

這種方式必須確保獲取鎖的線程必須確保進去臨界區之前沒有其它線程持有鎖,并且不能使用 read-modify-write的指令,只能使用read和write

當前Hotspot JVM中的在32位和64位有不同的形式
64bit為


32bit為

輕量鎖(thin locks),細節如前所述。它在HotSpot中使用displaced header的方式實現,又被稱作棧鎖

mark完整的狀態轉換關系如下

剛分配對象,此時對象是可偏向并且未偏向的

對象偏向于線程T,并記下epoch

此時有新線程來競爭

3.1一種策略是T執行對應的unlock,并重新分配給新的線程,以便不需要執行撤銷操作

3.2 如果已經偏向的對象被其它線程通過wait或者notify操作了,里面進入膨脹裝態,使用重量鎖

此時有新的線程來競爭,一種策略是使用啟發式的方式來統計撤銷的次數

4.1 當撤銷達到bulk rebias的閾值時,執行bulk rebias

4.2 當撤銷達到bulk revoke,并且此時所仍然被持有(原偏向鎖持有者),轉向輕量鎖(hashcode的計算依賴于膨脹來支持修改displaced mark word)

4.3 當撤銷達到bulk revoke,并且此時所沒有被持有(原偏向鎖持有者),轉向未被鎖定不可偏向的狀態,此時沒有進行hashcode計算

對于經過bulk rebias的對象,檢查期間沒有鎖定的實例,它的epoch會和class的不一樣,變成過期,但是可以偏向

5.1 如果 發生垃圾回收,lock會被初始化成可偏向但未偏向的狀態(這也可以降低epoch循環使用的影響)

5.2 如果重新被線程獲取偏向鎖,回到偏向鎖獲取狀態

處于輕量鎖狀態,它可能沒有hashcode計算,可能有,這依賴于inflat

6.1 沒有hashcode,此時解鎖回到沒有hashcode計算的不可偏向的狀態

6.2 又被其它線程占有,轉移到重量鎖(比如使用POXIS操作系統的mutex和condition)

未被鎖定不可偏向的狀態同時沒有hashcode計算加鎖后轉移到輕量鎖

處于重量鎖狀態

8.1 8.2 如果在Stop-The-Word期間沒有競爭了,就可以去膨脹(STW期間沒有其它線程獲取和釋放鎖,是安全的),根據是否有hashcode,退到對應的狀態(就是就退回使用偏向鎖 )

8.3 重量鎖期間的lock/unlock仍然處于重量鎖

計算過hashcode,再加鎖和解鎖對應狀態轉換(9.10)

附錄

Quickly Reacquirable Locks Dave Dice Mark Moir Bill Scherer

Eliminating_synchronization-related_atomic_operations_with_biased_locking_and_bulk_rebiasing

Evaluating and improving biased locking in the HotSpot virtual machine
biased-locking-in-hotspot

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/72753.html

相關文章

  • Synchronized原理分析

    摘要:而導致這個問題的原因是線程并行執行操作并不是原子的,存在線程安全問題。如果已經有線程持有了鎖,那這個線程會獨占鎖,直到鎖釋放完畢之前,其他線程都會被阻塞。當鎖處于重量級鎖狀態,其他線程嘗試獲取鎖時,都會被阻塞,也就是狀態。 1. 什么時候需要用SynchronizedSynchronized主要作用是在多個線程操作共享數據的時候,保證對共享數據訪問的線程安全性。比如兩個線程對于i這個共...

    everfly 評論0 收藏0
  • (五)Synchronized原理分析

    摘要:而導致這個問題的原因是線程并行執行操作并不是原子的,存在線程安全問題。表示自旋鎖,由于線程的阻塞和喚醒需要從用戶態轉為核心態,頻繁的阻塞和喚醒對來說性能開銷很大。 文章簡介 synchronized想必大家都不陌生,用來解決線程安全問題的利器。同時也是Java高級程序員面試比較常見的面試題。這篇文正會帶大家徹底了解synchronized的實現。 內容導航 什么時候需要用Synchr...

    greatwhole 評論0 收藏0
  • JAVA并發編程--2.synchronied實現原理

    摘要:實現原理虛擬機鎖原理虛擬機中對象頭部信息可以看見對象頭中結構中的成員,允許壓縮。否則,將偏向鎖撤銷,升級為輕量級鎖。存在明顯多線程競爭的場景下使用偏向鎖是不合適的,例如生產者消費者隊列。 synchronied實現原理 虛擬機鎖原理 虛擬機中對象頭部信息 /*hotspot/src/share/vm/oops/oop.hpp*/ class oopDesc { friend cla...

    mudiyouyou 評論0 收藏0
  • Java并發編程之旅總覽

    摘要:線程安全的概念什么時候線程不安全怎樣做到線程安全怎么擴展線程安全的類對線程安全的支持對線程安全支持有哪些中的線程池的使用與中線程池的生命周期與線程中斷中的鎖中常見死鎖與活鎖的實例線程同步機制顯示鎖使用與原理原理剖析原理中的與原理偏向鎖狀態 showImg(https://segmentfault.com/img/bVblUE9?w=1354&h=1660); 線程安全的概念 showI...

    Harpsichord1207 評論0 收藏0
  • 且聽我一個故事講透一個原理之synchronized

    摘要:第三天,太監傳話欽天監求見一日無事。第四天,欽天監一日無事。然后所有的競爭線程放棄自旋,逐個插入到對象里的一個隊列尾部,進入阻塞狀態。 微信公眾號:IT一刻鐘大型現實非嚴肅主義現場一刻鐘與你分享優質技術架構與見聞,做一個有劇情的程序員關注可第一時間了解更多精彩內容,定期有福利相送喲。 showImg(https://segmentfault.com/img/bVbrgsJ?w=900...

    gougoujiang 評論0 收藏0

發表評論

0條評論

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