自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

京東二面:Sychronized的鎖升級(jí)過(guò)程是怎樣的?

開(kāi)發(fā) 前端
Synchronized鎖升級(jí)機(jī)制是Java虛擬機(jī)為優(yōu)化多線程環(huán)境下同步操作性能而設(shè)計(jì)的一種動(dòng)態(tài)調(diào)整策略。

引言

Java作為主流的面向?qū)ο缶幊陶Z(yǔ)言,提供了豐富的并發(fā)工具來(lái)幫助開(kāi)發(fā)者解決多線程環(huán)境下的數(shù)據(jù)一致性問(wèn)題。其中,內(nèi)置的關(guān)鍵字"Synchronized"扮演了至關(guān)重要的角色,它能夠確保在同一時(shí)刻只有一個(gè)線程訪問(wèn)特定代碼塊或方法,從而有效地防止數(shù)據(jù)競(jìng)爭(zhēng)和保持內(nèi)存可見(jiàn)性。

在傳統(tǒng)的Synchronized實(shí)現(xiàn)中,由于其采用的是重量級(jí)鎖機(jī)制,每次獲取和釋放鎖都涉及操作系統(tǒng)層面的線程調(diào)度,這無(wú)疑增加了線程上下文切換的開(kāi)銷,尤其在高并發(fā)且鎖競(jìng)爭(zhēng)較小的場(chǎng)景下,可能會(huì)導(dǎo)致不必要的性能損失。為此,從Java 6開(kāi)始,JVM引入了鎖升級(jí)機(jī)制,這是一種動(dòng)態(tài)調(diào)整鎖狀態(tài)的技術(shù),旨在根據(jù)不同場(chǎng)景靈活運(yùn)用不同級(jí)別的鎖,從而在保證并發(fā)安全性的同時(shí),最大程度地提升程序的運(yùn)行效率。

本文將深入探討"Synchronized"的鎖升級(jí)過(guò)程,詳細(xì)介紹從無(wú)鎖狀態(tài)到偏向鎖、輕量級(jí)鎖,直至重量級(jí)鎖的不同階段及其背后的原理。

Synchronized鎖的基礎(chǔ)概念

在Java中,synchronized關(guān)鍵字是實(shí)現(xiàn)線程同步的關(guān)鍵機(jī)制之一,它用于確保多個(gè)線程在訪問(wèn)共享資源時(shí)的正確性和一致性。synchronized鎖的基本思想是,當(dāng)一個(gè)線程進(jìn)入某個(gè)synchronized代碼塊或方法時(shí),它必須首先獲取到該對(duì)象或類的鎖,然后才能執(zhí)行相應(yīng)的操作。如果其他線程試圖進(jìn)入相同的synchronized區(qū)域,它們將被阻塞,直到鎖被釋放。

對(duì)象頭與Mark Word簡(jiǎn)介

Java對(duì)象在內(nèi)存中不僅包含類實(shí)例的字段,還包含一些元數(shù)據(jù),這些元數(shù)據(jù)存儲(chǔ)在對(duì)象頭中。對(duì)象頭是Java對(duì)象的重要組成部分,它包含了關(guān)于對(duì)象的重要信息,如哈希碼、GC年齡以及鎖狀態(tài)等。其中,Mark Word是對(duì)象頭中的一個(gè)關(guān)鍵字段,它記錄了關(guān)于對(duì)象鎖狀態(tài)的信息。通過(guò)修改Mark Word的內(nèi)容,JVM能夠?qū)崿F(xiàn)對(duì)對(duì)象鎖的獲取和釋放。

Synchronized鎖定的基本原理與運(yùn)作機(jī)制概述

synchronized鎖定的基本原理是通過(guò)對(duì)對(duì)象或類的監(jiān)視器(Monitor)進(jìn)行加鎖和解鎖操作來(lái)實(shí)現(xiàn)線程同步。當(dāng)一個(gè)線程嘗試進(jìn)入synchronized代碼塊或方法時(shí),它會(huì)首先嘗試獲取對(duì)象或類的鎖。如果鎖已經(jīng)被其他線程持有,則該線程將被阻塞,直到鎖被釋放。synchronized鎖的運(yùn)作機(jī)制包括偏向鎖、輕量級(jí)鎖和重量級(jí)鎖三種狀態(tài)。偏向鎖適用于單線程訪問(wèn)的情況,輕量級(jí)鎖適用于多線程競(jìng)爭(zhēng)不激烈的情況,而重量級(jí)鎖則用于處理高競(jìng)爭(zhēng)場(chǎng)景。通過(guò)這三種狀態(tài)的轉(zhuǎn)換,synchronized鎖能夠根據(jù)不同的并發(fā)場(chǎng)景動(dòng)態(tài)調(diào)整鎖策略,以實(shí)現(xiàn)高效的線程同步。

關(guān)于synchronized的實(shí)現(xiàn)方式,原理介紹,請(qǐng)參考:美團(tuán)一面:說(shuō)說(shuō)_synchronized_的實(shí)現(xiàn)原理?問(wèn)麻了。。。。

鎖升級(jí)的概念

鎖升級(jí)是指Java虛擬機(jī)(JVM)在并發(fā)環(huán)境下對(duì)synchronized關(guān)鍵字所使用的鎖機(jī)制進(jìn)行動(dòng)態(tài)調(diào)整的過(guò)程,從最初的無(wú)鎖狀態(tài)逐漸過(guò)渡到偏向鎖、輕量級(jí)鎖,直至最終的重量級(jí)鎖。這一過(guò)程旨在根據(jù)實(shí)際的并發(fā)狀況選擇最適合的鎖類型,以實(shí)現(xiàn)對(duì)共享資源的最佳保護(hù)和最有效的并發(fā)控制。

鎖升級(jí)的主要目的是為了提升并發(fā)性能,減少不必要的線程上下文切換和內(nèi)存消耗。線程上下文切換是一個(gè)相對(duì)昂貴的操作,因?yàn)樗婕暗奖4娈?dāng)前線程的狀態(tài)、恢復(fù)另一個(gè)線程的狀態(tài)等一系列操作。通過(guò)優(yōu)化鎖策略,JVM可以減少這種切換的頻率,從而提高系統(tǒng)的整體性能。

另外,鎖升級(jí)也有助于減少內(nèi)存消耗。相較于重量級(jí)鎖需要?jiǎng)?chuàng)建額外的Monitor對(duì)象并在操作系統(tǒng)層面進(jìn)行線程調(diào)度,偏向鎖和輕量級(jí)鎖在一定程度上降低了內(nèi)存消耗,特別是對(duì)于大量短生命周期的鎖請(qǐng)求場(chǎng)景。

Synchronized鎖的四種狀態(tài)詳解

當(dāng)我們使用synchronized時(shí),Java虛擬機(jī)(JVM)會(huì)為每個(gè)被同步的對(duì)象維護(hù)一個(gè)鎖(或稱為監(jiān)視器鎖)。這個(gè)鎖有四種狀態(tài):從級(jí)別由低到高依次是:無(wú)鎖、偏向鎖,輕量級(jí)鎖,重量級(jí)鎖,用于控制多線程對(duì)共享資源的訪問(wèn)。

四種鎖狀態(tài)的轉(zhuǎn)換四種鎖狀態(tài)的轉(zhuǎn)換

無(wú)鎖

無(wú)鎖狀態(tài)是對(duì)象初始化后的默認(rèn)鎖狀態(tài),表示對(duì)象當(dāng)前未被任何線程鎖定。在這種狀態(tài)下,對(duì)象頭的鎖標(biāo)志位通常為空或特定的無(wú)鎖標(biāo)識(shí),表明對(duì)象不受任何同步控制,任何線程都能夠無(wú)障礙地訪問(wèn)該對(duì)象。

無(wú)鎖的標(biāo)志位為01,即如果是否偏向鎖標(biāo)識(shí)為0時(shí)是無(wú)鎖狀態(tài),為1時(shí)是偏向鎖。在這個(gè)狀態(tài)下,沒(méi)有線程擁有鎖,并且存儲(chǔ)了對(duì)象的hashcode、對(duì)象的分代年齡以及是否為偏向鎖的標(biāo)志(0表示不是偏向鎖)。

當(dāng)一個(gè)線程首次嘗試獲取鎖時(shí),JVM會(huì)檢查這個(gè)鎖是否處于無(wú)鎖狀態(tài)。如果是,JVM會(huì)嘗試將鎖偏向給這個(gè)線程,也就是將鎖標(biāo)記為偏向這個(gè)線程,并且將這個(gè)線程的ID記錄在鎖的標(biāo)記中。這樣,當(dāng)這個(gè)線程再次嘗試獲取鎖時(shí),就可以避免一些昂貴的操作,因?yàn)镴VM可以直接檢查鎖是否仍然偏向這個(gè)線程。

偏向鎖

當(dāng)一個(gè)線程首次成功獲取一個(gè)鎖時(shí),鎖就進(jìn)入了偏向鎖狀態(tài)。在偏向鎖狀態(tài)下,只有持有偏向鎖的線程才能再次獲取這個(gè)鎖,而不會(huì)引起競(jìng)爭(zhēng)。如果其他線程嘗試獲取這個(gè)鎖,偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖。

偏向鎖的標(biāo)志位為01,即是否偏向鎖表標(biāo)識(shí)位為1。與無(wú)鎖狀態(tài)的標(biāo)志位相同,但存儲(chǔ)的內(nèi)容有所不同。偏向鎖狀態(tài)下,會(huì)存儲(chǔ)偏向的線程ID、偏向時(shí)間戳、對(duì)象分代年齡以及是否偏向鎖的標(biāo)志(1)。

偏向鎖是一種針對(duì)線程獨(dú)占鎖優(yōu)化的機(jī)制,它適用于單一線程長(zhǎng)時(shí)間、連續(xù)地訪問(wèn)同一段同步代碼的情況。當(dāng)某個(gè)線程首次獲得同步代碼塊的鎖后,Java虛擬機(jī)會(huì)在對(duì)象頭的Mark Word中記錄該線程的ID,形成偏向鎖。在此之后,該線程再次進(jìn)入同步代碼塊時(shí),無(wú)需執(zhí)行CAS操作等復(fù)雜的同步動(dòng)作,僅需確認(rèn)Mark Word中的偏向線程ID是否為自己,便可迅速獲得鎖,從而極大地減少了獲取鎖的開(kāi)銷,提升了并發(fā)性能。

在偏向鎖生效期間,除非有其他線程嘗試獲取該鎖,否則持有偏向鎖的線程不會(huì)主動(dòng)釋放鎖。當(dāng)出現(xiàn)鎖競(jìng)爭(zhēng)時(shí),原有的偏向鎖持有者會(huì)經(jīng)歷撤銷過(guò)程。此過(guò)程發(fā)生在全局安全點(diǎn),即在所有線程均停止執(zhí)行字節(jié)碼的時(shí)刻,JVM會(huì)暫停當(dāng)前持有偏向鎖的線程,檢查鎖對(duì)象的狀態(tài)。如果發(fā)現(xiàn)持有偏向鎖的線程不再活動(dòng)或者鎖確實(shí)處于被爭(zhēng)奪狀態(tài),則會(huì)撤銷偏向鎖,即將對(duì)象頭恢復(fù)為無(wú)鎖狀態(tài)(標(biāo)志位為01)或直接升級(jí)為輕量級(jí)鎖(標(biāo)志位調(diào)整為對(duì)應(yīng)輕量級(jí)鎖的狀態(tài))。

偏向鎖主要是為了解決在一個(gè)線程連續(xù)多次獲取同一鎖的情況,降低不必要的同步操作開(kāi)銷。當(dāng)首次獲取鎖的線程再次進(jìn)入同步代碼塊時(shí),會(huì)檢查對(duì)象頭中存儲(chǔ)的線程ID是否與當(dāng)前線程一致。如果一致,則直接獲得鎖;如果不一致,則需要撤銷偏向鎖,重新進(jìn)行鎖競(jìng)爭(zhēng),可能升級(jí)為輕量級(jí)鎖。

優(yōu)點(diǎn): 對(duì)于沒(méi)有或很少發(fā)生鎖競(jìng)爭(zhēng)的場(chǎng)景,偏向鎖可以顯著減少鎖的獲取和釋放所帶來(lái)的性能損耗。

缺點(diǎn):

  • ? 額外存儲(chǔ)空間:偏向鎖會(huì)在對(duì)象頭中存儲(chǔ)一個(gè)偏向線程ID等相關(guān)信息,這部分額外的空間開(kāi)銷雖然較小,但在大規(guī)模并發(fā)場(chǎng)景下,累積起來(lái)也可能成為可觀的成本。
  • ? 鎖升級(jí)開(kāi)銷:當(dāng)一個(gè)偏向鎖的對(duì)象被其他線程訪問(wèn)時(shí),需要進(jìn)行撤銷(revoke)操作,將偏向鎖升級(jí)為輕量級(jí)鎖,甚至在更高競(jìng)爭(zhēng)情況下升級(jí)為重量級(jí)鎖。這個(gè)升級(jí)過(guò)程涉及到CAS操作以及可能的線程掛起和喚醒,會(huì)帶來(lái)一定的性能開(kāi)銷。
  • ? 適用場(chǎng)景有限:偏向鎖最適合于絕大部分時(shí)間只有一個(gè)線程訪問(wèn)對(duì)象的場(chǎng)景,這樣的情況下,偏向鎖的開(kāi)銷可以降到最低,有利于提高程序性能。但如果并發(fā)程度較高,或者線程切換頻繁,偏向鎖就可能不如輕量級(jí)鎖或重量級(jí)鎖高效。

輕量級(jí)鎖

當(dāng)一個(gè)線程嘗試獲取一個(gè)已經(jīng)被其他線程持有的偏向鎖時(shí),偏向鎖會(huì)升級(jí)為輕量級(jí)鎖。輕量級(jí)鎖是一種用于處理線程之間輕量級(jí)競(jìng)爭(zhēng)的機(jī)制。當(dāng)一個(gè)線程嘗試獲取輕量級(jí)鎖時(shí),它會(huì)先自旋一段時(shí)間,嘗試等待鎖被釋放。如果在這段時(shí)間內(nèi)鎖被釋放了,那么這個(gè)線程就可以成功獲取鎖。如果自旋結(jié)束后鎖仍然被持有,那么這個(gè)線程就會(huì)嘗試將鎖升級(jí)為重量級(jí)鎖。

輕量級(jí)鎖的標(biāo)識(shí)位為:00。當(dāng)鎖從偏向鎖升級(jí)為輕量級(jí)鎖時(shí),標(biāo)志位會(huì)變?yōu)?0。在輕量級(jí)鎖狀態(tài)下,多個(gè)線程可能會(huì)嘗試獲取鎖,通過(guò)自旋來(lái)等待鎖被釋放。

輕量級(jí)鎖利用CAS操作嘗試將對(duì)象頭的Mark Word替換為指向線程棧中鎖記錄的指針,如果CAS操作成功,則表示線程成功獲取鎖。獲取鎖失敗的線程會(huì)進(jìn)入自旋狀態(tài),不斷循環(huán)嘗試獲取鎖,直到獲取成功或升級(jí)為重量級(jí)鎖。在自旋期間,線程不會(huì)立即進(jìn)入阻塞狀態(tài),而是不斷循環(huán)檢查鎖是否可用。這種機(jī)制可以減少線程上下文切換的開(kāi)銷,但如果自旋次數(shù)過(guò)多或者競(jìng)爭(zhēng)加劇,自旋就會(huì)失去意義,JVM會(huì)選擇升級(jí)為重量級(jí)鎖。

優(yōu)點(diǎn):

? 低開(kāi)銷:輕量級(jí)鎖通過(guò)CAS操作嘗試獲取鎖,避免了重量級(jí)鎖中涉及的線程掛起和恢復(fù)等高昂開(kāi)銷。

? 快速響應(yīng):在無(wú)鎖競(jìng)爭(zhēng)或者鎖競(jìng)爭(zhēng)不激烈的情況下,輕量級(jí)鎖使得線程可以迅速獲取鎖并執(zhí)行同步代碼塊。

缺點(diǎn):

? 自旋消耗:當(dāng)鎖競(jìng)爭(zhēng)激烈時(shí),線程可能會(huì)長(zhǎng)時(shí)間自旋等待鎖,這會(huì)消耗CPU資源,導(dǎo)致性能下降。

? 升級(jí)開(kāi)銷:如果自旋等待超過(guò)一定閾值或者鎖競(jìng)爭(zhēng)加劇,輕量級(jí)鎖會(huì)升級(jí)為重量級(jí)鎖,這個(gè)升級(jí)過(guò)程本身也有一定的開(kāi)銷。

重量級(jí)鎖

當(dāng)輕量級(jí)鎖的自旋嘗試達(dá)到一定閾值,或者檢測(cè)到多個(gè)線程競(jìng)爭(zhēng)激烈時(shí),JVM會(huì)將輕量級(jí)鎖升級(jí)為重量級(jí)鎖。升級(jí)過(guò)程中,會(huì)取消當(dāng)前線程的自旋操作,并在對(duì)象頭中設(shè)置重量級(jí)鎖標(biāo)志。

重量級(jí)鎖的標(biāo)識(shí)位為:10。當(dāng)鎖從輕量級(jí)鎖升級(jí)為重量級(jí)鎖時(shí),標(biāo)志位會(huì)變?yōu)?0。在重量級(jí)鎖狀態(tài)下,線程在獲取鎖時(shí)會(huì)阻塞,直到持有鎖的線程釋放鎖。

在重量級(jí)鎖狀態(tài)下,線程在獲取鎖失敗時(shí)會(huì)被操作系統(tǒng)掛起,放入到該對(duì)象關(guān)聯(lián)的監(jiān)視器(Monitor)的等待隊(duì)列中,由操作系統(tǒng)進(jìn)行線程調(diào)度,當(dāng)鎖被釋放時(shí),操作系統(tǒng)會(huì)選擇合適的線程將其喚醒并授予鎖。

盡管重量級(jí)鎖的開(kāi)銷較大,涉及到線程上下文切換和內(nèi)核態(tài)用戶態(tài)的切換等,但它在高競(jìng)爭(zhēng)場(chǎng)景下能提供穩(wěn)定的互斥性和公平性,確保數(shù)據(jù)的一致性和線程的安全執(zhí)行。因此,即使性能損耗較高,也是在特定情況下必要的權(quán)衡措施。

優(yōu)點(diǎn):

? 強(qiáng)一致性:重量級(jí)鎖提供了最強(qiáng)的線程安全性,確保在多線程環(huán)境下數(shù)據(jù)的完整性和一致性。

? 簡(jiǎn)單易用:synchronized關(guān)鍵字的使用簡(jiǎn)潔明了,不易出錯(cuò)。

缺點(diǎn):

? 性能開(kāi)銷大:獲取和釋放重量級(jí)鎖時(shí)需要操作系統(tǒng)介入,可能涉及線程的掛起和喚醒,造成上下文切換,這對(duì)于頻繁鎖競(jìng)爭(zhēng)的場(chǎng)景來(lái)說(shuō)性能代價(jià)較高。

? 延遲較高:線程獲取不到鎖時(shí)會(huì)被阻塞,導(dǎo)致等待時(shí)間增加,進(jìn)而影響系統(tǒng)響應(yīng)速度。

以上四種鎖狀態(tài)優(yōu)缺點(diǎn)對(duì)比總結(jié)如下:

類型

優(yōu)點(diǎn)

缺點(diǎn)

使用場(chǎng)景

偏向鎖

快速:無(wú)須線程上下文切換,適合單一線程多次重復(fù)獲取同一線程鎖的場(chǎng)景

低開(kāi)銷:只需要檢查對(duì)象頭標(biāo)記

不適合多線程競(jìng)爭(zhēng)的場(chǎng)景

競(jìng)爭(zhēng)時(shí)需要撤銷偏向鎖,有一定開(kāi)銷

大多數(shù)時(shí)候只有一線程訪問(wèn)同步代碼塊,很少出現(xiàn)鎖競(jìng)爭(zhēng)的情況

輕量級(jí)鎖

較快:通過(guò)CAS操作和自旋避免了線程的阻塞與喚醒,減少了線程上下文切換

適用于鎖競(jìng)爭(zhēng)不激烈的場(chǎng)景

自旋可能導(dǎo)致CPU空耗,在高競(jìng)爭(zhēng)下,大量的線程自旋會(huì)增加系統(tǒng)負(fù)擔(dān)。

無(wú)法保證絕對(duì)的公平性

短時(shí)間的同步代碼塊,且鎖競(jìng)爭(zhēng)不激烈,期望快速重入和釋放

重量級(jí)鎖

穩(wěn)定可靠:嚴(yán)格保證互斥性和公平性

能夠有效應(yīng)對(duì)高度競(jìng)爭(zhēng)的鎖場(chǎng)景

開(kāi)銷大:涉及到線程上下文切換,性能較低

阻塞線程可能導(dǎo)致響應(yīng)時(shí)間變長(zhǎng)

高并發(fā)、高競(jìng)爭(zhēng)的場(chǎng)景,需要保證數(shù)據(jù)一致性,且線程等待鎖的時(shí)間較長(zhǎng)或不可預(yù)知

關(guān)于Java中鎖的分類,以及各種所得介紹,請(qǐng)參考:阿里二面:Java中_鎖的分類_有哪些?你能說(shuō)全嗎?

關(guān)于Java中如何定位以及避免死鎖,請(qǐng)參考:阿里二面:如何定位&避免_死鎖_?連著兩個(gè)面試問(wèn)到了!

鎖升級(jí)的具體步驟與流程

 1.無(wú)鎖到偏向鎖的升級(jí)流程:

? 當(dāng)線程首次嘗試獲取對(duì)象鎖時(shí),JVM首先檢查對(duì)象是否處于無(wú)鎖狀態(tài)。

? 若處于無(wú)鎖狀態(tài),JVM則立即將其標(biāo)記為偏向鎖,并記錄下當(dāng)前線程的ID。

? 這一過(guò)程通過(guò)CAS操作實(shí)現(xiàn),確保線程安全地更新對(duì)象頭的Mark Word為偏向鎖狀態(tài),并保存偏向線程的ID。

? 一旦設(shè)置成功,線程便可無(wú)阻礙地進(jìn)入同步代碼塊,后續(xù)再次獲取該鎖時(shí)僅需驗(yàn)證是否仍偏向當(dāng)前線程,無(wú)需額外同步操作

而對(duì)于偏向鎖的釋放機(jī)制:

? 當(dāng)持有偏向鎖的線程正常退出同步代碼塊時(shí),JVM僅簡(jiǎn)單地更新對(duì)象頭的訪問(wèn)計(jì)數(shù)等相關(guān)信息。

? 由于偏向鎖的設(shè)計(jì)初衷是優(yōu)化同一線程對(duì)鎖的反復(fù)獲取,因此它并不會(huì)立即釋放偏向關(guān)系,而是假設(shè)下一次仍由同一線程獲取鎖。

2. 偏向鎖到輕量級(jí)鎖的升級(jí)流程:

? 當(dāng)?shù)诙€(gè)線程嘗試獲取已被偏向的鎖時(shí),它會(huì)首先校驗(yàn)對(duì)象頭是否指向當(dāng)前線程的ID。

? 若校驗(yàn)失敗,表明鎖已偏向其他線程,此時(shí)需要撤銷偏向鎖。

? 撤銷后,對(duì)象會(huì)回到無(wú)鎖狀態(tài)或過(guò)渡至輕量級(jí)鎖狀態(tài)。

? 接著,新線程會(huì)嘗試在其棧幀中創(chuàng)建鎖記錄,并使用CAS操作將對(duì)象頭的Mark Word替換為指向該鎖記錄的指針。

? 若CAS操作成功,線程即獲得輕量級(jí)鎖;若失敗,則進(jìn)入自旋狀態(tài),循環(huán)嘗試獲取鎖。

對(duì)于輕量級(jí)鎖的釋放機(jī)制:

? 持有輕量級(jí)鎖的線程在退出同步代碼塊時(shí),會(huì)嘗試通過(guò)CAS操作將對(duì)象頭恢復(fù)為原始狀態(tài),即撤銷鎖記錄指針的替換。

? 若CAS操作成功,則輕量級(jí)鎖被順利釋放;否則,可能需要進(jìn)一步的鎖升級(jí)或處理。

3. 輕量級(jí)鎖到重量級(jí)鎖的升級(jí)流程:

? 當(dāng)輕量級(jí)鎖的持有線程退出同步代碼塊并釋放鎖時(shí),它會(huì)嘗試將對(duì)象頭恢復(fù)到無(wú)鎖或偏向鎖狀態(tài)。

? 若存在多個(gè)線程競(jìng)爭(zhēng)鎖資源,輕量級(jí)鎖的釋放可能導(dǎo)致自旋線程長(zhǎng)時(shí)間無(wú)法獲取鎖。

? JVM會(huì)綜合考量自旋次數(shù)、競(jìng)爭(zhēng)激烈程度以及系統(tǒng)負(fù)載等因素,決策是否將輕量級(jí)鎖升級(jí)為重量級(jí)鎖。

? 一旦升級(jí)為重量級(jí)鎖,原持有線程必須完成鎖的釋放。新來(lái)的線程將被阻塞,并被加入對(duì)象的監(jiān)視器(Monitor)等待隊(duì)列,由操作系統(tǒng)負(fù)責(zé)線程的調(diào)度管理。

對(duì)于釋放重量級(jí)鎖:

? 持有重量級(jí)鎖的線程在退出同步代碼塊時(shí),會(huì)通過(guò)調(diào)用Monitor的釋放操作來(lái)喚醒等待隊(duì)列中的下一個(gè)線程。

? 被喚醒的線程將獲得鎖并繼續(xù)執(zhí)行同步代碼,確保資源的順序訪問(wèn)和線程安全

鎖的升級(jí)流程鎖的升級(jí)流程

鎖降級(jí)與鎖消除

鎖降級(jí)

鎖降級(jí)通常出現(xiàn)在使用讀寫鎖(如Java中的ReentrantReadWriteLock)的場(chǎng)景中。在多線程環(huán)境下,一個(gè)線程首先獲取到了寫鎖,那么在它持有寫鎖期間,任何其他線程都無(wú)法獲取讀鎖或?qū)戞i,確保了對(duì)該資源的獨(dú)占訪問(wèn)權(quán)以進(jìn)行修改。這個(gè)在持有寫鎖的同時(shí),線程會(huì)嘗試獲取讀鎖。由于該線程已經(jīng)持有寫鎖,所以它可以成功獲取讀鎖,而不會(huì)造成死鎖或其他同步問(wèn)題。然后線程釋會(huì)放寫鎖,但仍持有讀鎖。此時(shí),其他線程可以獲取讀鎖進(jìn)行讀取操作,但無(wú)法獲取寫鎖進(jìn)行寫入操作。

鎖降級(jí)的意義在于,線程在完成寫操作后,如果接下來(lái)的任務(wù)主要是讀取而不是繼續(xù)寫入,那么通過(guò)降級(jí)能夠允許其他讀線程同時(shí)訪問(wèn)資源,提高了系統(tǒng)的并發(fā)性能,同時(shí)保證了數(shù)據(jù)一致性,因?yàn)樗凶x線程看到的都是最近一次寫操作完成后的一致性視圖。鎖降級(jí)是針對(duì)讀寫鎖的一種高級(jí)使用方式,用于提升多讀少寫的并發(fā)場(chǎng)景性能。

鎖消除

鎖消除(Lock Elimination)是一種由編譯器或虛擬機(jī)在運(yùn)行時(shí)進(jìn)行的優(yōu)化技術(shù),其目的是去除那些不必要的鎖操作。當(dāng)編譯器或JVM的即時(shí)編譯器(JIT Compiler)在分析代碼時(shí)發(fā)現(xiàn)某個(gè)鎖保護(hù)的變量并沒(méi)有發(fā)生實(shí)際的共享數(shù)據(jù)競(jìng)爭(zhēng),也就是說(shuō),該變量的生命周期僅限于方法內(nèi)部,不會(huì)逃逸出該方法,那么這個(gè)鎖就可以安全地被消除掉。

例如,如果一段同步代碼塊中的變量只在棧上分配并且沒(méi)有其他線程可以直接訪問(wèn),那么即使對(duì)該變量進(jìn)行了同步也不會(huì)帶來(lái)任何好處,反而增加了上下文切換和鎖獲取釋放的開(kāi)銷。在這種情況下,JVM可以通過(guò)逃逸分析等手段確定該變量不存在共享狀態(tài),進(jìn)而消除對(duì)它的同步操作。

鎖消除則是編譯器和JVM層面的一種優(yōu)化技術(shù),用于消除不必要的同步,減少鎖帶來(lái)的性能損耗。

總結(jié)

Synchronized鎖升級(jí)機(jī)制是Java虛擬機(jī)為優(yōu)化多線程環(huán)境下同步操作性能而設(shè)計(jì)的一種動(dòng)態(tài)調(diào)整策略。通過(guò)偏向鎖、輕量級(jí)鎖和重量級(jí)鎖之間的智能轉(zhuǎn)換,JVM可以根據(jù)實(shí)際的并發(fā)狀況在低競(jìng)爭(zhēng)和高競(jìng)爭(zhēng)場(chǎng)景下分別采取不同的鎖策略,從而有效減少線程上下文切換、內(nèi)存占用以及CPU空轉(zhuǎn)等問(wèn)題,提升系統(tǒng)的整體并發(fā)性能。

偏向鎖適用于單一線程反復(fù)訪問(wèn)同一鎖的情況,輕量級(jí)鎖則在輕度競(jìng)爭(zhēng)場(chǎng)景下通過(guò)CAS和自旋優(yōu)化鎖的獲取和釋放,而重量級(jí)鎖雖然開(kāi)銷較大,但在高強(qiáng)度競(jìng)爭(zhēng)下提供了嚴(yán)格的互斥性和線程調(diào)度的公平性。

責(zé)任編輯:武曉燕 來(lái)源: 碼農(nóng)Academy
相關(guān)推薦

2024-08-30 08:59:15

2024-09-09 08:15:20

2023-11-07 07:21:04

2024-10-29 09:42:50

2021-03-31 10:05:26

偏向鎖輕量級(jí)鎖

2024-06-27 08:55:41

2023-11-27 22:55:17

DNS域名解析

2023-11-08 08:18:19

鎖升級(jí)多線程

2024-11-20 16:00:19

MybatisJava數(shù)據(jù)庫(kù)

2021-07-01 19:30:23

JVM內(nèi)部鎖線程

2021-07-06 13:32:55

JVM

2024-09-11 08:17:09

2023-02-02 11:53:44

nolock關(guān)鍵詞SQLserver

2024-05-28 08:09:27

2025-03-28 10:47:05

開(kāi)發(fā)注解Java

2025-04-08 09:20:00

Sentinel限流微服務(wù)

2021-05-06 16:15:12

Java代碼

2022-03-08 08:44:13

偏向鎖Java內(nèi)置鎖

2021-04-25 09:58:48

mmapJava面試

2021-03-17 15:54:32

IO零拷貝方式
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)