日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

《Java并发编程的艺术》之synchronized的底层实现原理

發(fā)布時間:2023/12/10 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《Java并发编程的艺术》之synchronized的底层实现原理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在學(xué)習(xí)鎖優(yōu)化時,對象頭(Mark Word) 是必不可缺的一環(huán),因?yàn)閟ynchronized 用的鎖是存在對象頭里的。32位的虛擬機(jī)上對象頭占64位(8字節(jié)),64位的虛擬機(jī)上對象頭占128位(16字節(jié))[^objectHead];而不同的類型,對象頭的布局不太一樣:

  • 數(shù)組類型:Mark Word、Class Metadata Address、Array Length
  • 普通類型:Mark Word、Class Metadata Address

Mark Word 表示對象的HashCode 或 鎖信息
Class Metadata Address 表示對象的數(shù)據(jù)類型在方法區(qū)對應(yīng)的地址
Array Length 表示數(shù)組的長度(只在對象是數(shù)組的情況下才會存在)

對象頭的默認(rèn)表示應(yīng)該如下所示

鎖狀態(tài)25bit4bit1bit是否是偏向鎖2bit 鎖標(biāo)志位
無狀態(tài)鎖對象的hashcode對象分代年齡001

具體的對象內(nèi)存布局看這篇文章

而根據(jù)JVM的設(shè)置1,具體分配時又會有不同的情況,如下所示

當(dāng)關(guān)閉了偏向鎖的設(shè)置,那么就會走左邊的流程;反之則走右邊的流程。

偏向鎖

由于大多數(shù)情況下,鎖大多都不處于多線程競爭狀態(tài),而且總是由同一個線程獲取,所以JVM在1.6之后加入了偏向鎖輕量鎖 ,如今總共由4種鎖狀態(tài):無狀態(tài)鎖偏向鎖輕量鎖重量鎖。隨著線程競爭的提升,鎖會逐漸升級(無法降級)。
偏向鎖在沒有競爭的情況下可以提高同步的性能,這方面主要體現(xiàn)在偏向鎖只需要進(jìn)行一次CAS而輕量鎖需要兩次。它是一個需要權(quán)衡利弊的選擇,它不是在任何情況下都對程序有利的。如果競爭很多,那么撤銷偏向鎖的過程就會成為性能瓶頸。

當(dāng)偏向鎖可用時,初始化的對象頭分配如下所示

鎖狀態(tài)23bit2bit4bit1bit 是否是偏向鎖2bit 鎖標(biāo)志位
偏向鎖線程IDepoch對象分代年齡101

加鎖過程

  • 當(dāng)對象頭的isBiased 為1時且鎖狀態(tài)為01時,偏向鎖可用,繼續(xù)后面的流程
  • 判斷目標(biāo)對象頭是否包含本線程ID,如果沒有,則直接CAS往對象頭里寫入本線程ID。到這一步加鎖就結(jié)束了
  • 鎖撤銷

    由于偏向鎖使用了一種直到競爭發(fā)生時才會釋放的機(jī)制,所以當(dāng)其他線程競爭偏向鎖時,持有偏向鎖的線程才會去釋放鎖。

  • 等待原持有偏向鎖的線程(后文簡稱原線程)運(yùn)行至全局安全點(diǎn)(safe point)
  • 暫停原線程
  • 檢查原線程 的線程狀態(tài),如果退出了同步代碼塊,則重偏向;反之升級為輕量鎖
  • 恢復(fù)原線程
  • 輕量鎖

    加鎖過程

    注意:輕量鎖會一直保持,喚醒總是發(fā)生在輕量鎖解鎖的時候,因?yàn)榧渔i的時候已經(jīng)成功CAS操作;而CAS失敗的線程,會立即鎖膨脹,并阻塞等待喚醒。

  • 第一次進(jìn)入同步塊,開辟一個叫做Lock Record 的空間用于存儲鎖記錄
  • 將對象頭中的Mark Word 復(fù)制到 當(dāng)前線程棧中
  • 嘗試用CAS將Mark Word 替換為 指向Lock Record的指針
  • 第三步操作成功,則將Mark Word 設(shè)置為00狀態(tài),標(biāo)識輕量鎖
  • 然后執(zhí)行同步體
  • 第三部操作失敗,進(jìn)入自旋獲取鎖
  • 自旋獲取鎖的失敗次數(shù)到達(dá)閾值,膨脹鎖,修改為重量級鎖(狀態(tài)改為10
  • 線程阻塞
  • 鎖釋放過程

  • 嘗試CAS將Lock Record的Owner 復(fù)制回 Mark Word
  • 如果CAS操作成功,則表示沒有競爭發(fā)生;否則看步驟3
  • 釋放鎖并喚醒等待的線程
  • 總結(jié)

    本章是對synchronized 在JVM里的各種等級及升級的流程進(jìn)行了講解,其中主要是通過控制對象頭的一些狀態(tài)來控制鎖的等級。偏向鎖通過標(biāo)記Thread ID 來表示,當(dāng)前對象已經(jīng)被對應(yīng)線程占用;輕量鎖則替換Mark Word 為 Lock Record 地址 來表示當(dāng)前對象被對應(yīng)線程占用。無論是哪種鎖,在不同的場景下有不同的需求,可以參考以下表格做出選擇

    偏向鎖:

    • 優(yōu)點(diǎn):加鎖和解鎖不需要額外消耗,和執(zhí)行非同步方法相比,僅存在納秒級的差距
    • 缺點(diǎn):如果線程間存在競爭,會帶來額外開銷(偏向鎖的撤銷)
    • 適用場景: 適用于只有一個線程訪問同步塊的場景

    輕量鎖:

    • 優(yōu)點(diǎn): 競爭的線程不會造成阻塞,提高了程序的響應(yīng)速度
    • 缺點(diǎn): 如果始終得不到鎖,使用自旋會消耗CPU
    • 適用場景: 追求相應(yīng)實(shí)踐,同步塊執(zhí)行速度非常快

    重量鎖:

    • 優(yōu)點(diǎn): 線程競爭不使用自選,不會消耗CPU
    • 缺點(diǎn): 線程阻塞,響應(yīng)時間緩慢
    • 適用場景: 追求吞吐量,同步塊執(zhí)行速度較慢

    這個是網(wǎng)上找到的關(guān)于鎖撤銷、膨脹等操作的總流程


  • 關(guān)于偏向鎖的相關(guān)JVM設(shè)置:-XXBiasedLockingStartupDelay=0表示啟動程序幾秒鐘后激活偏向鎖-XXUseBiasedLocking=false表示關(guān)閉偏向鎖(確定會發(fā)生競爭時可以這么設(shè)置)?

  • 轉(zhuǎn)載于:https://www.cnblogs.com/codeleven/p/10963092.html

    總結(jié)

    以上是生活随笔為你收集整理的《Java并发编程的艺术》之synchronized的底层实现原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。