當(dāng)前位置:首頁 > 公眾號(hào)精選 > 小林coding
[導(dǎo)讀]一文了解synchronized。

引子

小艾和小牛在路上相遇,小艾一臉沮喪。

小牛:小艾小艾,發(fā)生甚么事了?

小艾:別提了,昨天有個(gè)面試官問了我好幾個(gè)關(guān)于 synchronized 關(guān)鍵字的問題,沒答上來。

小艾:我后來查了很多資料,有二十多頁的概念說明,也有三十來頁的源碼剖析,看得我頭大。

小牛:你那看的是死知識(shí),不好用,你得聽我的總結(jié)。

小艾:看來是有備而來,那您給講講吧。

小牛:那咱們開始!


synchronized關(guān)鍵字引入

我們知道,在多線程程序中往往會(huì)出現(xiàn)這么一個(gè)情況:多個(gè)線程同時(shí)訪問某個(gè)線程間的共享變量。來舉個(gè)例子吧:

假設(shè)銀行存款業(yè)務(wù)寫了兩個(gè)方法,一個(gè)是存錢 store() 方法 ,一個(gè)是查詢余額 get() 方法。假設(shè)初始客戶小明的賬戶余額為 0 元。(PS:這個(gè)例子只是個(gè) toy demo,為了方便大家理解寫的,真實(shí)的業(yè)務(wù)場景不會(huì)這樣。)

????//?account?客戶在銀行的存款?
????public?void?store(int?money){
????????int?newAccount=account+money;
????????account=newAccount;
????}
????public?void?get(){
????????System.out.print("小明的銀行賬戶余額:");
????????System.out.print(account);
????}

如果小明為自己存款 1 元,我們期望的線程調(diào)用情況如下:

  1. 首先會(huì)啟動(dòng)一個(gè)線程調(diào)用 store() 方法,為客戶賬戶余額增加 1;

  2. 再啟動(dòng)一個(gè)線程調(diào)用 get() 方法,輸出客戶的新余額為 1。

但實(shí)際情況可能由于線程執(zhí)行的先后順序,出現(xiàn)如圖所示的錯(cuò)誤:

小明存錢流程
小明:咱家沒錢了

小明會(huì)驚奇的以為自己的錢沒存上。這就是一個(gè)典型的由共享數(shù)據(jù)引發(fā)的并發(fā)數(shù)據(jù)沖突問題。

解決方式也很簡單,讓并發(fā)執(zhí)行會(huì)產(chǎn)生問題的代碼段不并發(fā)行了。

如果 store() 方法 執(zhí)行完,才能執(zhí)行 get() 方法,而不是像上圖一樣并發(fā)執(zhí)行,自然不會(huì)出現(xiàn)這個(gè)問題。那如何才能做到呢?

答案就是使用 synchronized 關(guān)鍵字。

我們先從直覺上思考一下,如果要實(shí)現(xiàn)先執(zhí)行 store() 方法,再執(zhí)行 get() 方法的話該怎么設(shè)計(jì)。

我們可以設(shè)置某個(gè)鎖,鎖會(huì)有兩種狀態(tài),分別是上鎖解鎖。在 store() 方法執(zhí)行之前,先觀察這個(gè)鎖的狀態(tài),如果是上鎖狀態(tài),就進(jìn)入阻塞,代碼不運(yùn)行;

如果這把鎖是解鎖狀態(tài),那就先將這把鎖狀態(tài)變?yōu)樯湘i,之后接著運(yùn)行自己的代碼。運(yùn)行完成之后再將鎖狀態(tài)設(shè)置為解鎖。

對(duì)于 get() 方法也是如此。

Java 中的 synchronized 關(guān)鍵字就是基于這種思想設(shè)計(jì)的。在 synchronized 關(guān)鍵字中,鎖就是一個(gè)對(duì)象。

synchronized 一共有三種使用方法:

  • 直接修飾某個(gè)實(shí)例方法。像上文代碼一樣,在這種情況下多線程并發(fā)訪問實(shí)例方法時(shí),如果其他線程調(diào)用同一個(gè)對(duì)象的被 synchronized 修飾的方法,就會(huì)被阻塞。相當(dāng)于把鎖記錄在這個(gè)方法對(duì)應(yīng)的對(duì)象上。

????//?account?客戶在銀行的存款?
????public?synchronized?void?store(int?money){
????????int?newAccount=account+money;
????????account=newAccount;
????}
????public?synchronized?void?get(){
????????System.out.print("小明的銀行賬戶余額:");
????????System.out.print(account);
????}
  • 直接修飾某個(gè)靜態(tài)方法。在這種情況下進(jìn)行多線程并發(fā)訪問時(shí),如果其他線程也是調(diào)用屬于同一類的被 synchronized 修飾的靜態(tài)方法,就會(huì)被阻塞。相當(dāng)于把鎖信息記錄在這個(gè)方法對(duì)應(yīng)的類上。

????public?synchronized?static?void?get(){
????????···
????}
  • 修飾代碼塊。如果此時(shí)有別的線程也想訪問某個(gè)被synchronized(對(duì)象0)修飾的同步代碼塊時(shí),也會(huì)被阻塞。

????public?static?void?get(){
????????synchronized(對(duì)象0){
????????????···
????????}
????}

小艾問:我看了不少參考書還有網(wǎng)上資料,都說 synchronized 的鎖是鎖在對(duì)象上的。關(guān)于這句話,你能深入講講嗎?

小?;卮鸬溃簞e急,我先講講 Java 對(duì)象在內(nèi)存中的表示。


Java 對(duì)象在內(nèi)存中的表示

講清 synchronized 關(guān)鍵字的原理前需要理清 Java 對(duì)象在內(nèi)存中的表示方法。

Java 對(duì)象在內(nèi)存中的表示

上圖就是一個(gè) Java 對(duì)象在內(nèi)存中的表示。我們可以看到,內(nèi)存中的對(duì)象一般由三部分組成,分別是對(duì)象頭、對(duì)象實(shí)際數(shù)據(jù)和對(duì)齊填充。

對(duì)象頭包含 Mark Word、Class Pointer和 Length 三部分。

  • Mark Word 記錄了對(duì)象關(guān)于鎖的信息,垃圾回收信息等。

  • Class Pointer 用于指向?qū)ο髮?duì)應(yīng)的 Class 對(duì)象(其對(duì)應(yīng)的元數(shù)據(jù)對(duì)象)的內(nèi)存地址。

  • Length只適用于對(duì)象是數(shù)組時(shí),它保存了該數(shù)組的長度信息。

對(duì)象實(shí)際數(shù)據(jù)包括了對(duì)象的所有成員變量,其大小由各個(gè)成員變量的大小決定。

對(duì)齊填充表示最后一部分的填充字節(jié)位,這部分不包含有用信息。

我們剛才講的鎖 synchronized 鎖使用的就是對(duì)象頭的 Mark Word 字段中的一部分。

Mark Word 中的某些字段發(fā)生變化,就可以代表鎖不同的狀態(tài)。

由于鎖的信息是記錄在對(duì)象里的,有的開發(fā)者也往往會(huì)說鎖住對(duì)象這種表述。

無鎖狀態(tài)的 Mark Word

這里我們以無鎖狀態(tài)的 Mark Word 字段舉例:

如果當(dāng)前對(duì)象是無鎖狀態(tài),對(duì)象的 Mark Word 如圖所示。

無鎖狀態(tài)的 Mark Word 字段

我們可以看到,該對(duì)象頭的 Mark Word 字段分為四個(gè)部分:

  1. 對(duì)象的 hashCode ;

  2. 對(duì)象的分代年齡,這部分用于對(duì)對(duì)象的垃圾回收;

  3. 是否為偏向鎖位,1代表是,0代表不是;

  4. 鎖標(biāo)志位,這里是 01。


synchronized關(guān)鍵字的實(shí)現(xiàn)原理

講完了 Java 對(duì)象在內(nèi)存中的表示,我們下一步來講講 synchronized 關(guān)鍵字的實(shí)現(xiàn)原理。

從前文中我們可以看到, synchronized 關(guān)鍵字有兩種修飾方法

  1. 直接作為關(guān)鍵字修飾在方法上,將整個(gè)方法作為同步代碼塊:

????public?synchronized?static?void?`get()`{
????????···
????}
  1. 修飾在同步代碼塊上。

????public?static?void?`get()`{
????????synchronized(對(duì)象0){
????????????···
????????}
????}

針對(duì)這兩種情況,Java 編譯時(shí)的處理方法并不相同。

對(duì)于第一種情況,編譯器會(huì)為其自動(dòng)生成了一個(gè) ACC_SYNCHRONIZED 關(guān)鍵字用來標(biāo)識(shí)。

在 JVM 進(jìn)行方法調(diào)用時(shí),當(dāng)發(fā)現(xiàn)調(diào)用的方法被 ACC_SYNCHRONIZED 修飾,則會(huì)先嘗試獲得鎖。

對(duì)于第二種情況,編譯時(shí)在代碼塊開始前生成對(duì)應(yīng)的1個(gè) monitorenter 指令,代表同步塊進(jìn)入。2個(gè) monitorexit 指令,代表同步塊退出。

這兩種方法底層都需要一個(gè) reference 類型的參數(shù),指明要鎖定和解鎖的對(duì)象。

如果 synchronized 明確指定了對(duì)象參數(shù),那就是該對(duì)象。

如果沒有明確指定,那就根據(jù)修飾的方法是實(shí)例方法還是類方法,取對(duì)應(yīng)的對(duì)象實(shí)例或類對(duì)象(Java 中類也是一種特殊的對(duì)象)作為鎖對(duì)象。

確定鎖定和解鎖的對(duì)象

每個(gè)對(duì)象維護(hù)著一個(gè)記錄著被鎖次數(shù)的計(jì)數(shù)器。當(dāng)一個(gè)線程執(zhí)行 monitorenter,該計(jì)數(shù)器自增從 0 變?yōu)?1;

當(dāng)一個(gè)線程執(zhí)行 monitorexit,計(jì)數(shù)器再自減。當(dāng)計(jì)數(shù)器為 0 的時(shí)候,說明對(duì)象的鎖已經(jīng)釋放。

小艾問:為什么會(huì)有兩個(gè) monitorexit 指令呢?

小牛答:正常退出,得用一個(gè) monitorexit 吧,如果中間出現(xiàn)異常,鎖會(huì)一直無法釋放。所以編譯器會(huì)為同步代碼塊添加了一個(gè)隱式的 try-finally 異常處理,在 finally 中會(huì)調(diào)用 monitorexit 命令最終釋放鎖。

重量級(jí)鎖

小艾問:那么問題來了,之前你說鎖的信息是記錄在對(duì)象的 Mark Word 中的,那現(xiàn)在冒出來的 monitor 又是什么呢?

小牛答:我們先來看一下重量級(jí)鎖對(duì)應(yīng)對(duì)象的 Mark Word。

在 Java 的早期版本中,synchronized 鎖屬于重量級(jí)鎖,此時(shí)對(duì)象的 Mark Word 如圖所示。

重量級(jí)鎖的 Mark Word 字段

我們可以看到,該對(duì)象頭的 Mark Word 分為兩個(gè)部分。第一部分是指向重量級(jí)鎖的指針,第二部分是鎖標(biāo)記位。

而這里所說的指向重量級(jí)鎖的指針就是 monitor。

英文詞典翻譯 monitor 是監(jiān)視器。Java 中每個(gè)對(duì)象會(huì)對(duì)應(yīng)一個(gè)監(jiān)視器。

這個(gè)監(jiān)視器其實(shí)也就是監(jiān)控鎖有沒有釋放,釋放的話會(huì)通知下一個(gè)等待鎖的線程去獲取。

monitor 的成員變量比較多,我們可以這樣理解:

monitor結(jié)構(gòu)

我們可以將 monitor 簡單理解成兩部分,第一部分表示當(dāng)前占用鎖的線程,第二部分是等待這把鎖的線程隊(duì)列。

如果當(dāng)前占用鎖的線程把鎖釋放了,那就需要在線程隊(duì)列中喚醒下一個(gè)等待鎖的線程。

但是阻塞或喚醒一個(gè)線程需要依賴底層的操作系統(tǒng)來實(shí)現(xiàn),Java 的線程是映射到操作系統(tǒng)的原生線程之上的。

而操作系統(tǒng)實(shí)現(xiàn)線程之間的切換需要從用戶態(tài)轉(zhuǎn)換到核心態(tài),這個(gè)狀態(tài)轉(zhuǎn)換需要花費(fèi)很多的處理器時(shí)間,甚至可能比用戶代碼執(zhí)行的時(shí)間還要長。

由于這種效率太低,Java 后期做了改進(jìn),我再來詳細(xì)講一講。


CAS算法

在講其他改進(jìn)之前,我們先來聊聊 CAS 算法。CAS 算法全稱為 Compare And Swap。

顧名思義,該算法涉及到了兩個(gè)操作,比較(Compare)和交換(Swap)。

怎么理解這個(gè)操作呢?我們來看下圖:

CAS 算法

我們知道,在對(duì)共享變量進(jìn)行多線程操作的時(shí)候,難免會(huì)出現(xiàn)線程安全問題。

對(duì)該問題的一種解決策略就是對(duì)該變量加鎖,保證該變量在某個(gè)時(shí)間段只能被一個(gè)線程操作。

但是這種方式的系統(tǒng)開銷比較大。因此開發(fā)人員提出了一種新的算法,就是大名鼎鼎的 CAS 算法。

CAS 算法的思路如下:

  1. 該算法認(rèn)為線程之間對(duì)變量的操作進(jìn)行競爭的情況比較少。

  2. 算法的核心是對(duì)當(dāng)前讀取變量值 E 和內(nèi)存中的變量舊值 V 進(jìn)行比較。

  3. 如果相等,就代表其他線程沒有對(duì)該變量進(jìn)行修改,就將變量值更新為新值 N。

  4. 如果不等,就認(rèn)為在讀取值 E 到比較階段,有其他線程對(duì)變量進(jìn)行過修改,不進(jìn)行任何操作。

當(dāng)線程運(yùn)行 CAS 算法時(shí),該運(yùn)行過程是原子操作,原子操作的含義就是線程開始跑這個(gè)函數(shù)后,運(yùn)行過程中不會(huì)被別的程序打斷。

我們來看看實(shí)際上 Java 語言中如何使用這個(gè) CAS 算法,這里我們以 AtomicInteger 類中的 compareAndSwapInt() 方法舉例:

public?final?native?boolean?compareAndSwapInt
(Object?var1,?long?var2,?int?var3,?int?var4)

可以看到,該函數(shù)原型接受四個(gè)參數(shù):

  1. 第一個(gè)參數(shù)是一個(gè) AtomicInteger 對(duì)象。

  2. 第二個(gè)參數(shù)是該 AtomicInteger 對(duì)象對(duì)應(yīng)的成員變量在內(nèi)存中的地址。

  3. 第三個(gè)參數(shù)是上圖中說的線程之前讀取的值 P

  4. 第四個(gè)參數(shù)是上圖中說的線程計(jì)算的新值 V。


偏向鎖

JDK 1.6 中提出了偏向鎖的概念。該鎖提出的原因是,開發(fā)者發(fā)現(xiàn)多數(shù)情況下鎖并不存在競爭,一把鎖往往是由同一個(gè)線程獲得的。

如果是這種情況,不斷的加鎖解鎖是沒有必要的。

那么能不能讓 JVM 直接負(fù)責(zé)在這種情況下加解鎖的事情,不讓操作系統(tǒng)插手呢?

因此開發(fā)者設(shè)計(jì)了偏向鎖。偏向鎖在獲取資源的時(shí)候,會(huì)在資源對(duì)象上記錄該對(duì)象是否偏向該線程。

偏向鎖并不會(huì)主動(dòng)釋放,這樣每次偏向鎖進(jìn)入的時(shí)候都會(huì)判斷該資源是否是偏向自己的,如果是偏向自己的則不需要進(jìn)行額外的操作,直接可以進(jìn)入同步操作。

下圖表示偏向鎖的 Mark Word結(jié)構(gòu):

偏向鎖的 Mark Word 字段

可以看到,偏向鎖對(duì)應(yīng)的 Mark Word 包含該偏向鎖對(duì)應(yīng)的線程 ID、偏向鎖的時(shí)間戳和對(duì)象分代年齡。

偏向鎖的申請(qǐng)流程

我們再來看一下偏向鎖的申請(qǐng)流程:

  1. 首先需要判斷對(duì)象的 Mark Word 是否屬于偏向模式,如果不屬于,那就進(jìn)入輕量級(jí)鎖判斷邏輯。否則繼續(xù)下一步判斷;

  2. 判斷目前請(qǐng)求鎖的線程 ID 是否和偏向鎖本身記錄的線程 ID 一致。如果一致,繼續(xù)下一步的判斷,如果不一致,跳轉(zhuǎn)到步驟4;

  3. 判斷是否需要重偏向,重偏向邏輯在后面一節(jié)批量重偏向和批量撤銷會(huì)說明。如果不用的話,直接獲得偏向鎖;

  4. 利用 CAS 算法將對(duì)象的 Mark Word 進(jìn)行更改,使線程 ID 部分換成本線程 ID。如果更換成功,則重偏向完成,獲得偏向鎖。如果失敗,則說明有多線程競爭,升級(jí)為輕量級(jí)鎖。

偏向鎖的申請(qǐng)流程

值得注意的是,在執(zhí)行完同步代碼后,線程不會(huì)主動(dòng)去修改對(duì)象的 Mark Word,讓它重回?zé)o鎖狀態(tài)。

所以一般執(zhí)行完 synchronized 語句后,如果是偏向鎖的狀態(tài)的話,線程對(duì)鎖的釋放操作可能是什么都不做。

匿名偏向鎖

在 JVM 開啟偏向鎖模式下,如果一個(gè)對(duì)象被新建,在四秒后,該對(duì)象的對(duì)象頭就會(huì)被置為偏向鎖。

一般來說,當(dāng)一個(gè)線程獲取了一把偏向鎖時(shí),會(huì)在對(duì)象頭和棧幀中的鎖記錄里不僅說明目前是偏向鎖狀態(tài),也會(huì)存儲(chǔ)鎖偏向的線程 ID。

在 JVM 四秒自動(dòng)創(chuàng)建偏向鎖的情況下,線程 ID 為0。

由于這種情況下的偏向鎖不是由某個(gè)線程求得生成的,這種情況下的偏向鎖也稱為匿名偏向鎖。

批量重偏向和批量撤銷

生產(chǎn)者消費(fèi)者模式下,生產(chǎn)者線程負(fù)責(zé)對(duì)象的創(chuàng)建,消費(fèi)者線程負(fù)責(zé)對(duì)生產(chǎn)出來的對(duì)象進(jìn)行使用。

當(dāng)生產(chǎn)者線程創(chuàng)建了大量對(duì)象并執(zhí)行加偏向鎖的同步操作,消費(fèi)者對(duì)對(duì)象使用之后,會(huì)產(chǎn)生大量偏向鎖執(zhí)行和偏向鎖撤銷的問題。

大量偏向鎖執(zhí)行和偏向鎖撤銷的問題

Russell K和 Detlefs D在他們的文章提出了批量重偏向和批量撤銷的過程。

在上圖情景下,他們探討了能不能直接將偏向的線程換成消費(fèi)者的線程。

替換不是一件容易事,需要在 JVM 的眾多線程中找到類似上文情景的線程。

他們最后提出的解決方法是:

以類為單位,為每個(gè)類維護(hù)一個(gè)偏向鎖撤銷計(jì)數(shù)器,每一次該類的對(duì)象發(fā)生偏向撤銷操作時(shí),該計(jì)數(shù)器計(jì)數(shù) +1,當(dāng)這個(gè)計(jì)數(shù)值達(dá)到重偏向閾值時(shí),JVM 就認(rèn)為該類可能不適合正常邏輯,適合批量重偏向邏輯。這就是對(duì)應(yīng)上圖流程圖里的是否需要重偏向過程。

以生產(chǎn)者消費(fèi)者為例,生產(chǎn)者生產(chǎn)同一類型的對(duì)象給消費(fèi)者,然后消費(fèi)者對(duì)這些對(duì)象都需要執(zhí)行偏向鎖撤銷,當(dāng)撤銷過程過多時(shí)就會(huì)觸發(fā)上文規(guī)則,JVM 就注意到這個(gè)類了。

批量重偏向和批量撤銷

具體規(guī)則是:

  1. 每個(gè)類對(duì)象會(huì)有一個(gè)對(duì)應(yīng)的 epoch 字段,每個(gè)處于偏向鎖狀態(tài)對(duì)象的 Mark Word 中也有該字段,其初始值為創(chuàng)建該對(duì)象時(shí),類對(duì)象中的 epoch 的值。

  2. 每次發(fā)生批量重偏向時(shí),就將類對(duì)象的 epoch 字段 +1,得到新的值 epoch_new。

  3. 遍歷 JVM 中所有線程的棧,找到該類對(duì)象,將其 epoch 字段改為新值。根據(jù)線程棧的信息判斷出該線程是否鎖定了該對(duì)象,將現(xiàn)在偏向鎖還在被使用的對(duì)象賦新值 epoch_new。

  4. 下次有線程想獲得鎖時(shí),如果發(fā)現(xiàn)當(dāng)前對(duì)象的 epoch 值和類的 epoch 不相等,不會(huì)執(zhí)行撤銷操作,而是直接通過 CAS 操作將其 Mark Word 的 Thread ID 改成當(dāng)前線程 ID。

批量撤銷相對(duì)于批量重偏向好理解得多,JVM 也會(huì)統(tǒng)計(jì)重偏向的次數(shù)。

假設(shè)該類計(jì)數(shù)器計(jì)數(shù)繼續(xù)增加,當(dāng)其達(dá)到批量撤銷的閾值后(默認(rèn)40),JVM 就認(rèn)為該類的使用場景存在多線程競爭,會(huì)標(biāo)記該類為不可偏向,之后對(duì)于該類的鎖升級(jí)為輕量級(jí)鎖。


輕量級(jí)鎖

輕量級(jí)鎖的設(shè)計(jì)初衷在于并發(fā)程序開發(fā)者的經(jīng)驗(yàn)“對(duì)于絕大部分的鎖,在整個(gè)同步周期內(nèi)都是不存在競爭的”。

所以它的設(shè)計(jì)出發(fā)點(diǎn)也在線程競爭情況較少的情況下。我們先來看一下輕量級(jí)鎖的 Mark Word 布局。

如果當(dāng)前對(duì)象是輕量級(jí)鎖狀態(tài),對(duì)象的 Mark Word 如下圖所示。

輕量級(jí)鎖 Mark Word 字段

我們可以看到,該對(duì)象頭Mark Word分為兩個(gè)部分。第一部分是指向棧中的鎖記錄的指針,第二部分是鎖標(biāo)記位,針對(duì)輕量級(jí)鎖該標(biāo)記位為 00。

小艾問:那這指向棧中的鎖記錄的指針是什么意思呢?

小牛答:這得結(jié)合輕量級(jí)鎖的上鎖步驟來慢慢講。

如果當(dāng)前這個(gè)對(duì)象的鎖標(biāo)志位為 01(即無鎖狀態(tài)或者輕量級(jí)鎖狀態(tài)),線程在執(zhí)行同步塊之前,JVM 會(huì)先在當(dāng)前的線程的棧幀中創(chuàng)建一個(gè) Lock Record,包括一個(gè)用于存儲(chǔ)對(duì)象頭中的 Mark Word 以及一個(gè)指向?qū)ο蟮闹羔槨?/p>

Lock Record

然后 JVM 會(huì)利用 CAS 算法對(duì)這個(gè)對(duì)象的 Mark Word 進(jìn)行修改。如果修改成功,那該線程就擁有了這個(gè)對(duì)象的鎖。我們來看一下如果上圖的線程執(zhí)行 CAS 算法成功的結(jié)果。

執(zhí)行 CAS 算法

當(dāng)然 CAS 也會(huì)有失敗的情況。如果 CAS 失敗,那就說明同時(shí)執(zhí)行 CAS 操作的線程可不止一個(gè)了, Mark Word 也做了更改。

首先虛擬機(jī)會(huì)檢查對(duì)象的 Mark Word 字段指向棧中的鎖記錄的指針是否指向當(dāng)前線程的棧幀。如果是,那就說明可能出現(xiàn)了類似 synchronized 中套 synchronized 情況:

synchronized?(對(duì)象0)?{
????synchronized?(對(duì)象0)?{
????????···
????}
}

當(dāng)然這種情況下當(dāng)前線程已經(jīng)擁有這個(gè)對(duì)象的鎖,可以直接進(jìn)入同步代碼塊執(zhí)行。

否則說明鎖被其他線程搶占了,該鎖還需要升級(jí)為重量級(jí)鎖。

和偏向鎖不同的是,執(zhí)行完同步代碼塊后,需要執(zhí)行輕量級(jí)鎖的解鎖過程。解鎖過程如下:

  1. 通過 CAS 操作嘗試把線程棧幀中復(fù)制的 Mark Word 對(duì)象替換當(dāng)前對(duì)象的 Mark Word。

  2. 如果 CAS 算法成功,整個(gè)同步過程就完成了。

  3. 如果 CAS 算法失敗,則說明存在競爭,鎖升級(jí)為重量級(jí)鎖。

我們來總結(jié)一下輕量級(jí)鎖升級(jí)過程吧:

輕量級(jí)鎖的升級(jí)過程

總結(jié)

這次我們了解了 synchronized 底層實(shí)現(xiàn)原理和對(duì)應(yīng)的鎖升級(jí)過程。最后我們再通過這張流程圖來回顧一下 synchronized 鎖升級(jí)過程吧。

鎖申請(qǐng)完整流程

巨人肩膀
  1. 實(shí)現(xiàn)Java虛擬機(jī):JVM故障診斷與性能優(yōu)化

  2. 深入理解java虛擬機(jī) JVM高級(jí)特性與最佳實(shí)踐

  3. Russell K , Detlefs D . Eliminating synchronization-related atomic operations with biased locking and bulk rebiasing[C]// Acm Sigplan Conference on Object-oriented Programming Systems. ACM, 2006.

  4. Dice D , Moir M S , Scherer Iii W N . Quickly reacquirable locks: US 2010.

  5. https://github.com/farmerjohngit/myblog/issues/12

  6. https://www.itqiankun.com/article/bias-lightweight-synchronized-lock

  7. https://www.itqiankun.com/article/bias-lock-epoch-effect

  8. https://www.hollischuang.com/archives/1883

  9. http://www.ideabuffer.cn/2017/05/06/Java%E5%AF%B9%E8%B1%A1%E5%86%85%E5%AD%98%E5%B8%83%E5%B1%80/

  10. http://www.ideabuffer.cn/2017/04/21/java-%E4%B8%AD%E7%9A%84%E9%94%81-%E5%81%8F%E5%90%91%E9%94%81%E3%80%81%E8%BD%BB%E9%87%8F%E7%BA%A7%E9%94%81%E3%80%81%E8%87%AA%E6%97%8B%E9%94%81%E3%80%81%E9%87%8D%E9%87%8F%E7%BA%A7%E9%94%81/

  11. https://blog.csdn.net/zhao_miao/article/details/84500771


推薦閱讀
帶寬、延時(shí)、吞吐率、PPS 這些都是啥?
讀者問:小林怎么學(xué)操作系統(tǒng)和計(jì)算機(jī)網(wǎng)絡(luò)呀?
讀者問:小林你的 500 張圖是怎么畫的?
讀者問:小林你能分享做公眾號(hào)的經(jīng)驗(yàn)嗎?

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場,如有問題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉