Java?Synchronize底層原理總結(jié)
對(duì)象內(nèi)存結(jié)構(gòu)
對(duì)象頭:MarkWord
存儲(chǔ)對(duì)象頭的信息,Klass Word
描述對(duì)象實(shí)例的具體類型
實(shí)例數(shù)據(jù):成員變量
對(duì)齊填充:如果對(duì)象頭 + 實(shí)例變量 不是 8 的整數(shù)倍,則通過對(duì)齊填充補(bǔ)齊
MarkWord 解析
hashcode
:25位的對(duì)象標(biāo)識(shí)Hash碼age
:對(duì)象分代年齡占4位biased_lock
:偏向鎖標(biāo)識(shí),占1位,0表示沒有開始偏向鎖,1表示開啟了偏向鎖thread
:持有偏向鎖的線程ID,占23位epoch
:偏向時(shí)間戳,占2位ptr_to_lock_record:
輕量級(jí)鎖狀態(tài)下,指向棧中鎖記錄的指針,占30位ptr_to_heavyweight_monitor
:重量級(jí)鎖狀態(tài)下,指向?qū)ο蟊O(jiān)視器Monitor的指針,占30位
LockRecord 鎖記錄
Markword:記錄鎖記錄的地址
對(duì)象引用:引用被加上鎖了的對(duì)象
重量級(jí)鎖
Monitor
Monitor 監(jiān)視器,是由 jvm 提供的,由 C++ 實(shí)現(xiàn)的,有三個(gè)實(shí)現(xiàn)部分
WaitSet
:調(diào)用了 wait 方法的線程在這里等待,處于 WAITED 狀態(tài)
EntryList
:沒有搶到對(duì)象鎖的線程在這里等待,處于 BLOCKED 狀態(tài)
Owner
:存儲(chǔ)已經(jīng)搶到鎖的線程對(duì)象
Monitor
的實(shí)現(xiàn)屬于重量級(jí)鎖,涉及到 內(nèi)核態(tài)和用戶態(tài)的切換,線程的上下文切換,每個(gè) Java
對(duì)象都會(huì)關(guān)聯(lián)一個(gè) Monitor
對(duì)象,如果使用 Synchronize
給該對(duì)象加鎖,那么 Java
對(duì)象上面的 MarkWord
地址就被設(shè)置為指向該 Monitor
對(duì)象的指針
輕量級(jí)鎖
加鎖流程:
- 在線程棧中創(chuàng)建一個(gè)
Lock Record
對(duì)象,它的object reference
字段指向鎖對(duì)象 - 通過 CAS 指令把
Lock Record
的地址存放到對(duì)象頭的Markword
中,如果是無鎖狀態(tài)則修改成功,代表該線程獲取了輕量級(jí)鎖 - 如果當(dāng)前線程已經(jīng)持有該鎖,就代表是一次鎖重入,設(shè)置
Lock Record
的第一部分為null
,起到一個(gè)重入計(jì)數(shù)器的作用 - 如果
CAS
修改失敗,則說明發(fā)生了競爭,需要膨脹為重量級(jí)鎖
解鎖過程:
- 遍歷線程棧,找到所有
object reference
字段等于當(dāng)前鎖對(duì)象的Lock record
- 如果
Lock record
的MarkWord
為null
,代表這是一次重入,將obj
設(shè)置為null
后continue
即可 - 如果
Lock record
的Markword
不為null
,則利用CAS
指令將對(duì)象頭的markword
與對(duì)象對(duì)象頭的markword
進(jìn)行替換,如果成功則恢復(fù)為無鎖狀態(tài),如果失敗則膨脹為重量級(jí)鎖
Markword 記錄
開始時(shí)的狀態(tài)
替換后的狀態(tài)
偏向鎖
背景:輕量級(jí)鎖在沒有競爭的時(shí)候,每次重入都需要進(jìn)行 CAS
操作
Java 6
中 引入偏向鎖來做進(jìn)一步的優(yōu)化:只有第一次 操才使用 CAS
將線程 ID 設(shè)置到對(duì)象的 markword
頭,之后發(fā)現(xiàn)這個(gè)線程 ID 是自己就不會(huì)產(chǎn)生競爭,不用重新 CAS
,以后只要不發(fā)生競爭,這個(gè)對(duì)象就歸這個(gè)線程所有
代碼示例:
public class Thread5 { private static final Object object = new Object(); public static void method1() { synchronized (object) { method2(); } } public static void method2() { synchronized (object) { method3(); } } public static void method3() { synchronized (object) { } } }
總結(jié)
Java 中的 Synchronize 有偏向鎖、輕量級(jí)鎖、重量級(jí)鎖三種形式,分別對(duì)應(yīng)了鎖只被一個(gè)線程持有、不同線程交替持有鎖、多線程競爭的情況
重量級(jí)鎖:底層使用 Monitor
實(shí)現(xiàn),里面涉及到了用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換、進(jìn)程的上下文切換,成本較高,性能比較低
輕量級(jí)鎖:線程加鎖時(shí)間是錯(cuò)開的(也就是沒有競爭),可以用輕量級(jí)鎖來優(yōu)化,輕量級(jí)修改了對(duì)象頭的鎖標(biāo)志,相對(duì)重量級(jí)鎖性能提升了許多,每次修改都是 CAS
操作,保證原子性
偏向鎖:一段很長的時(shí)間內(nèi)都只被一個(gè)線程使用鎖,可以使用偏向鎖,第一次獲得鎖時(shí),會(huì)有一個(gè) CAS
操作,之后該線程再獲取鎖,只需要判斷 mark word
中是否是自己的線程 id 即可,而不是開銷相對(duì)較大的 CAS 命令
以上就是Java Synchronize底層原理總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Java Synchronize底層原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot定制化Starter實(shí)現(xiàn)方法
小伙伴們?cè)?jīng)可能都經(jīng)歷過整天寫著CURD的業(yè)務(wù),都沒寫過一些組件相關(guān)的東西,這篇文章記錄一下SpringBoot如何自定義一個(gè)Starter。原理和理論就不用多說了,可以在網(wǎng)上找到很多關(guān)于該方面的資料,這里主要分享如何自定義2023-01-01SpringCloud服務(wù)接口調(diào)用OpenFeign及使用詳解
這篇文章主要介紹了SpringCloud服務(wù)接口調(diào)用——OpenFeign,在學(xué)習(xí)Ribbon時(shí),服務(wù)間調(diào)用使用的是RestTemplate+Ribbon實(shí)現(xiàn),而Feign在此基礎(chǔ)上繼續(xù)進(jìn)行了封裝,使服務(wù)間調(diào)用變得更加方便,需要的朋友可以參考下2023-04-04詳解SpringMVC注解版前臺(tái)向后臺(tái)傳值的兩種方式
本篇文章主要介紹了詳解SpringMVC注解版前臺(tái)向后臺(tái)傳值的兩種方式,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-04-04.NET Core使用SignalR實(shí)現(xiàn)實(shí)時(shí)通訊的示例代碼
SignalR是一個(gè)ASP.NETCore庫,用于在客戶端和服務(wù)器之間實(shí)現(xiàn)實(shí)時(shí)通訊,本文主要介紹了.NETCore中使用SignalR實(shí)現(xiàn)實(shí)時(shí)通訊,感興趣的可以了解一下2024-11-11SpringCloud Config分布式配置中心使用教程介紹
springcloud config是一個(gè)解決分布式系統(tǒng)的配置管理方案。它包含了 client和server兩個(gè)部分,server端提供配置文件的存儲(chǔ)、以接口的形式將配置文件的內(nèi)容提供出去,client端通過接口獲取數(shù)據(jù)、并依據(jù)此數(shù)據(jù)初始化自己的應(yīng)用2022-12-12Spring Security 自定義短信登錄認(rèn)證的實(shí)現(xiàn)
這篇文章主要介紹了Spring Security 自定義短信登錄認(rèn)證的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03解決springdataJPA對(duì)原生sql支持的問題
這篇文章主要介紹了解決springdataJPA對(duì)原生sql支持的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06