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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

java

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

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

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

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

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

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

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

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

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

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

偏向鎖

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

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

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

加鎖過(guò)程

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

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

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

    加鎖過(guò)程

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

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

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

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

    偏向鎖:

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

    輕量鎖:

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

    重量鎖:

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

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


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

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

    總結(jié)

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

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