網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
文章目錄
- Synchronized鎖優(yōu)化
- (1)引言
- (2)Java對(duì)象的內(nèi)存布局
- (3)偏向鎖
- (4)輕量級(jí)鎖
- (5)重量級(jí)鎖
Synchronized鎖優(yōu)化
(1)引言
在JDK1.5之前,synchronized的底層實(shí)現(xiàn)都是重量級(jí)的,借助操作系統(tǒng)底層實(shí)現(xiàn),也稱(chēng)之為synchronized為重量級(jí)鎖,在JDK1.5之后,對(duì)Synchronized進(jìn)行了各種優(yōu)化,實(shí)現(xiàn)的原理是鎖升級(jí)的過(guò)程,有了偏向鎖、輕量級(jí)鎖和重量級(jí)鎖的概念。
(2)Java對(duì)象的內(nèi)存布局
在Java中,創(chuàng)建一個(gè)對(duì)象后,在JVM中,對(duì)象在內(nèi)存中的存儲(chǔ)布局,分為三塊:
- 對(duì)象頭區(qū)域: 存放鎖信息、對(duì)象年齡等信息。
- 實(shí)例數(shù)據(jù)區(qū)域: 存儲(chǔ)的是對(duì)象的真正有效的信息,比如對(duì)象中所有字段內(nèi)容。
-
對(duì)齊填充區(qū)域: JVM規(guī)定對(duì)象的起始地址必須是
8字節(jié)
的整數(shù)倍,如果一個(gè)對(duì)象實(shí)際占用的內(nèi)存大小不是8字節(jié)的整數(shù)倍,就“補(bǔ)位”到8字節(jié)的整數(shù)倍,對(duì)齊填充區(qū)域的大小不是固定的。
synchronized
用的鎖是存在對(duì)象頭里,如果對(duì)象是數(shù)組類(lèi)型,對(duì)象頭中還包含了數(shù)組長(zhǎng)度。
如果是數(shù)組類(lèi)型,則虛擬機(jī)使用3個(gè)字寬存儲(chǔ)對(duì)象頭,如果不是數(shù)組類(lèi)型,則占用2個(gè)字寬存儲(chǔ)對(duì)象頭,在32位系統(tǒng)下,1字寬等于4字節(jié)即32bit位。
在Java對(duì)象頭中Mark Word是默認(rèn)存儲(chǔ)對(duì)象的
hashcode
,分代年齡
和鎖的標(biāo)記位
。32位JVM中Mark Word默認(rèn)存儲(chǔ)的結(jié)構(gòu)如下圖所示:
在Java SE1.6中,鎖一共存在4種狀態(tài),級(jí)別從低到高依次是:無(wú)鎖狀態(tài)、偏向鎖狀態(tài)、輕量級(jí)鎖狀態(tài)和重量級(jí)鎖狀態(tài),這幾個(gè)狀態(tài)隨著競(jìng)爭(zhēng)的情況逐漸升級(jí),鎖是可以升級(jí)的但是不能降級(jí),意味著偏向鎖升級(jí)成輕量級(jí)鎖再升級(jí)為重量級(jí)鎖,目的是為了提高獲取鎖和釋放鎖的效率。
(3)偏向鎖
偏向鎖的操作是無(wú)需操作系統(tǒng)介入的,每個(gè)對(duì)象都有對(duì)象頭,對(duì)象頭中的Mark Word區(qū)域存儲(chǔ)對(duì)象的鎖信息。
該對(duì)象頭先處于無(wú)鎖狀態(tài),當(dāng)有線(xiàn)程來(lái)訪(fǎng)問(wèn),JVM使用CAS操作將線(xiàn)程ID記錄到Mark Word中,修改偏向鎖的標(biāo)識(shí)位,當(dāng)前線(xiàn)程就擁有了這把鎖
??注意:將線(xiàn)程ID通過(guò)CAS記錄,變更偏向鎖標(biāo)識(shí)為1。JVM不用和操作系統(tǒng)協(xié)商設(shè)置monitor,只需要記錄下線(xiàn)程ID,就表示當(dāng)前線(xiàn)程擁有這把鎖,不用操作系統(tǒng)介入獲取鎖的線(xiàn)程就可以進(jìn)入到程序代碼塊中執(zhí)行,當(dāng)線(xiàn)程再次執(zhí)行時(shí),JVM通過(guò)鎖對(duì)象的Mark Word判斷,如果當(dāng)前線(xiàn)程ID還存在,就說(shuō)明該線(xiàn)程還持有著這個(gè)對(duì)象的鎖,就直接進(jìn)入臨界區(qū)執(zhí)行,這個(gè)就是偏向鎖,在沒(méi)有別的線(xiàn)程競(jìng)爭(zhēng)的時(shí)候,一直偏向當(dāng)前的線(xiàn)程可以一直執(zhí)行。
優(yōu)點(diǎn):只有一個(gè)線(xiàn)程執(zhí)行同步塊時(shí)進(jìn)一步提高性能,適用于一個(gè)線(xiàn)程反復(fù)獲取同一個(gè)鎖的情況,偏向鎖可以提高帶有同步但無(wú)競(jìng)爭(zhēng)的程序的性能。
(4)輕量級(jí)鎖
如果在偏向鎖中一個(gè)線(xiàn)程A一直執(zhí)行過(guò)程中,此時(shí)又來(lái)了另一個(gè)線(xiàn)程B要進(jìn)入代碼塊中執(zhí)行,但是鎖對(duì)象保存的是線(xiàn)程A的線(xiàn)程ID,還是偏向鎖,這時(shí)候就導(dǎo)致線(xiàn)程B無(wú)法執(zhí)行,這個(gè)時(shí)候就需要對(duì)偏向鎖進(jìn)行升級(jí),變成一個(gè)輕量級(jí)鎖。
JVM把鎖對(duì)象恢復(fù)成無(wú)鎖狀態(tài),在當(dāng)前的兩個(gè)線(xiàn)程的棧幀中各分配一個(gè)空間,叫做Lock Record,把鎖對(duì)象的Mark Word在兩個(gè)線(xiàn)程的棧幀中各復(fù)制一份,叫做Displaced Mark Word,將當(dāng)前線(xiàn)程A的Lock Record的地址使用CAS放到鎖對(duì)象的Mark Word當(dāng)中,并且將鎖的標(biāo)識(shí)設(shè)置為00,意味著當(dāng)前線(xiàn)程A獲取到輕量級(jí)鎖,可以進(jìn)入到臨界區(qū)執(zhí)行。
線(xiàn)程B沒(méi)有獲取到鎖,但不阻塞,JVM會(huì)讓他自旋幾次,等待一會(huì)兒,當(dāng)線(xiàn)程A退出了臨界區(qū)釋放鎖的時(shí)候,需要將Displaced Mark Word使用CAS復(fù)制回去,接下來(lái)線(xiàn)程B就可以通過(guò)CAS復(fù)制信息。這個(gè)時(shí)候兩個(gè)線(xiàn)程就可以交替進(jìn)入臨界區(qū),執(zhí)行代碼。偏向鎖即使出現(xiàn)了競(jìng)爭(zhēng),想獲取鎖只要自旋幾次,等待一會(huì),鎖就可以是釋放,使用CAS和Lock Record就可以避免重量級(jí)鎖的開(kāi)銷(xiāo)。
優(yōu)點(diǎn):絕大部分的鎖在整個(gè)生命周期中都存在少量競(jìng)爭(zhēng),在多線(xiàn)程交替執(zhí)行同步代碼塊是可以避免重量級(jí)鎖引起的性能問(wèn)題。
(5)重量級(jí)鎖
輕量級(jí)鎖在運(yùn)行時(shí),線(xiàn)程A正在持有鎖,另一個(gè)線(xiàn)程B自旋了好多次,線(xiàn)程A還沒(méi)有釋放鎖,這個(gè)時(shí)候JVM考慮自旋次數(shù)太多浪費(fèi)CPU資源,就需要將鎖升級(jí)為重量級(jí)鎖,重量級(jí)鎖需要操作系統(tǒng)的介入,依賴(lài)操作系統(tǒng)底層的mutex lock,JVM會(huì)創(chuàng)建一個(gè)monitor對(duì)象,把這個(gè)對(duì)象的地址信息更新到Mark Word中,并將鎖標(biāo)志置為10。
線(xiàn)程A還在持有鎖運(yùn)行,線(xiàn)程B直接掛起,線(xiàn)程進(jìn)入阻塞,釋放掉占用的CPU資源。
原文鏈接:https://blog.csdn.net/sheng0113/article/details/124674155
相關(guān)推薦
- 2022-10-10 使用Pyinstaller打包exe文件詳細(xì)圖文教程_python
- 2023-03-05 Golang中tinyrpc框架的源碼解讀詳解_Golang
- 2022-11-01 Python正則表達(dá)中re模塊的使用_python
- 2023-10-13 CSS點(diǎn)擊切換或隱藏盒子的卷起、展開(kāi)效果
- 2022-07-08 Python3?Loguru輸出日志工具的使用_python
- 2022-12-14 C++利用類(lèi)實(shí)現(xiàn)矩陣的數(shù)乘,乘法以及點(diǎn)乘_C 語(yǔ)言
- 2022-06-29 python版單鏈表反轉(zhuǎn)_python
- 2022-11-24 redis使用skiplist跳表的原因解析_Redis
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支