国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java 中 synchronized 的優(yōu)化操作:鎖升級、鎖消除、鎖粗化

這篇具有很好參考價(jià)值的文章主要介紹了Java 中 synchronized 的優(yōu)化操作:鎖升級、鎖消除、鎖粗化。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

由 并發(fā)編程中常見的鎖策略 總結(jié)可知,synchronized 具有以下幾個(gè)特性:

  1. 開始時(shí)是樂觀鎖,如果鎖沖突頻繁,就轉(zhuǎn)換為悲觀鎖。
  2. 開始是輕量級鎖實(shí)現(xiàn),如果鎖被持有的時(shí)間較長,就轉(zhuǎn)換成重量級鎖。
  3. 實(shí)現(xiàn)輕量級鎖時(shí),大概率用自旋鎖策略。
  4. 是一種不公平鎖。
  5. 是一種可重入鎖。
  6. 不是讀寫鎖。

本文介紹synchronized的幾種優(yōu)化操作,包括鎖升級、鎖消除和鎖粗化。

一、鎖升級

JVM 將 synchronized 鎖分為無鎖、偏向鎖、輕量級鎖、重量級鎖這四種狀態(tài)。在加鎖過程中,會根據(jù)實(shí)際情況,依次進(jìn)行升級。(**目前主流的 JVM 的實(shí)現(xiàn),只能鎖升級,不能鎖降級!**不是無法實(shí)現(xiàn),只不過可能是因?yàn)榇嬖谝恍┐鷥r(jià),使得這樣做的收益和代價(jià)不成比例,因此就沒有實(shí)現(xiàn)。)

整體的加鎖過程(鎖升級過程):剛開始加鎖,是偏向鎖狀態(tài);遇到鎖競爭后,升級成自旋鎖(輕量級鎖);當(dāng)競爭更激烈時(shí),就會變成重量級鎖(交給內(nèi)核阻塞等待)。

Java 中 synchronized 的優(yōu)化操作:鎖升級、鎖消除、鎖粗化,# JavaWeb,java,開發(fā)語言,并發(fā)編程,多線程,synchronized

1、偏向鎖(Biased Locking)

第一個(gè)嘗試加鎖的線程優(yōu)先進(jìn)入偏向鎖狀態(tài)。偏向鎖是Java虛擬機(jī)(JVM)中用于提高線程同步性能的一種優(yōu)化技術(shù)。在多線程環(huán)境中,對共享資源進(jìn)行同步操作,需要使用鎖(synchronized)來保證線程的互斥訪問。傳統(tǒng)的鎖機(jī)制存在競爭和上下文切換的開銷,對性能會有一定的影響。而偏向鎖則是為了減少無競爭情況下的鎖操作開銷而引入的。

偏向鎖不是真的“加鎖”,只是先讓線程針對鎖對象有個(gè)標(biāo)記,記錄某個(gè)鎖屬于哪個(gè)線程。

它的基本思想是,當(dāng)一個(gè)線程獲取鎖并訪問同步代碼塊時(shí),如果沒有競爭,那么下次該線程再次進(jìn)入同步塊時(shí),無需再次獲取鎖。這是因?yàn)樵跓o競爭的情況下,假設(shè)一個(gè)線程反復(fù)訪問同步代碼塊,無需每次都去競爭鎖,只需判斷鎖是否處于偏向狀態(tài);如果是,那么直接進(jìn)入同步代碼塊即可。

通俗來說就是,如果后續(xù)沒有其他線程再來競爭該鎖,那么就不用真的加鎖了,從而避免了加鎖解鎖的開銷。 但一旦還有其他線程來嘗試競爭這個(gè)鎖,偏向鎖就立即升級成真的鎖(輕量級鎖),此時(shí)別的線程就只能等待了。這樣做既保證了效率,也保證了線程安全。

如何判定有沒有別的線程來競爭該鎖?

注意,偏向鎖是synchronized內(nèi)部做的工作。synchronized會針對某個(gè)對象進(jìn)行加鎖,這個(gè)所謂的“偏向鎖”正是在這個(gè)對象里頭做一個(gè)標(biāo)記。

由于一開始已經(jīng)在鎖對象中記錄了當(dāng)前鎖屬于哪個(gè)線程,因此很容易識別當(dāng)前申請鎖的線程是否是一開始就記錄了的線程。

如果另一個(gè)線程正在嘗試對同一個(gè)對象進(jìn)行加鎖,也會先嘗試做標(biāo)記,但結(jié)果卻發(fā)現(xiàn)已經(jīng)有標(biāo)記了。于是JVM就會通知先來的線程,讓它趕快把鎖升級一下。

偏向鎖本質(zhì)上是“延遲加鎖”,即能不加鎖就不加鎖,盡量避免不必要的加鎖開銷;但是該做的標(biāo)記還是得做的,否則就無法區(qū)分何時(shí)需要真正加鎖。

舉個(gè)栗子理解偏向鎖

假設(shè)男主是一個(gè)鎖,女主是一個(gè)線程。如果只有女主和男主曖昧(即只有這一個(gè)線程來使用這個(gè)鎖),那么即使男主和女主不領(lǐng)證結(jié)婚(避免了高成本操作),也可以一直生活下去。

但是如果此時(shí)有女配出現(xiàn),也嘗試競爭男主,想和男主搞曖昧,那么此時(shí)女主就必須當(dāng)機(jī)立斷,不管領(lǐng)證結(jié)婚這個(gè)操作成本多高,也勢必要把這個(gè)動作完成(即真正加鎖),讓女配死心。

所以說,偏向鎖 = 搞曖昧~~

2、自旋鎖

**什么是自旋鎖?**在鎖策略的文章中提到:

自旋鎖是一種典型的輕量級鎖的實(shí)現(xiàn)方式,它通常是純用戶態(tài)的,不需要經(jīng)過內(nèi)核態(tài)。按之前的方式,線程在搶鎖失敗后即進(jìn)入阻塞狀態(tài),放棄 CPU,需要過很久才能再次被調(diào)度。但實(shí)際上,在大部分情況下雖然當(dāng)前搶鎖失敗,但過不了很久鎖就會被釋放,沒必要就放棄 CPU。這個(gè)時(shí)候就可以使用自旋鎖來處理這樣的問題。

自旋鎖是一種忙等待鎖的機(jī)制。當(dāng)一個(gè)線程需要獲取自旋鎖時(shí),它會反復(fù)地檢查鎖是否可用,而不是立即被阻塞。如果獲取鎖失?。ㄦi已經(jīng)被其他線程占用),當(dāng)前線程會立即再嘗試獲取鎖,不斷自旋(空轉(zhuǎn))等待鎖的釋放,直到獲取到鎖為止。第一次獲取鎖失敗,第二次的嘗試會在極短的時(shí)間內(nèi)到來。這樣能保證一旦鎖被其他線程釋放,當(dāng)前線程能第一時(shí)間獲取到鎖。

優(yōu)點(diǎn):沒有放棄 CPU,不涉及線程阻塞和調(diào)度。一旦鎖被釋放就能第一時(shí)間獲取到鎖。
缺點(diǎn):如果鎖被其他線程持有的時(shí)間比較久,那么就會持續(xù)的消耗 CPU 資源(忙等),而掛起等待的時(shí)候是不消耗 CPU 的。

自旋鎖適用于保護(hù)臨界區(qū)較小、鎖占用時(shí)間短的情況,因?yàn)樽孕龝腃PU資源。自旋鎖通常使用原子操作或特殊的硬件指令來實(shí)現(xiàn)。

隨著其他線程進(jìn)入鎖競爭,偏向鎖狀態(tài)會被消除,進(jìn)入輕量級鎖狀態(tài),即自適應(yīng)的自旋鎖。

此處的輕量級鎖是通過 CAS 來實(shí)現(xiàn)。通過 CAS 檢查并更新一塊內(nèi)存 (比如比較 null 與該線程引用是否相等),如果更新成功,則認(rèn)為加鎖成功;如果更新失敗,則認(rèn)為鎖被占用,繼續(xù)自旋式的等待,期間并不放棄 CPU 資源。

(見 詳解CAS算法)

Java 中 synchronized 的優(yōu)化操作:鎖升級、鎖消除、鎖粗化,# JavaWeb,java,開發(fā)語言,并發(fā)編程,多線程,synchronized

由于自旋操作是一直讓 CPU 空轉(zhuǎn),比較浪費(fèi) CPU 資源,因此此處的自旋不會一直持續(xù)進(jìn)行,而是達(dá)到一定的時(shí)間或重試次數(shù)就不再自旋了。這也就是所謂的 “自適應(yīng)”。

3、重量級鎖

**什么是重量級鎖 ?**在鎖策略的文章中提到:

簡單來說,輕量級鎖是加鎖解鎖的過程更快更高效的鎖策略,而重量級鎖是加鎖解鎖的過程更慢更低效的鎖策略。重量級鎖中加鎖機(jī)制重度依賴 OS 提供的 mutex(互斥量)。

  • 大量的內(nèi)核態(tài)用戶態(tài)切換。
  • 很容易引發(fā)線程的調(diào)度。

這兩個(gè)操作的成本都比較高,而且一旦涉及到用戶態(tài)和內(nèi)核態(tài)的切換,效率就低了。

如果競爭進(jìn)一步激烈,自旋不能快速獲取到鎖狀態(tài)。就會膨脹為重量級鎖。

自旋鎖雖然能最快獲取到鎖,但是要消耗大量 CPU(因?yàn)樽孕臅r(shí)候CPU是快速空轉(zhuǎn)的)。如果當(dāng)前鎖競爭非常激烈,比如 50 個(gè)線程競爭一個(gè)鎖,1 個(gè)爭上,另外 49 個(gè)等待。這么多線程都在自旋空轉(zhuǎn),CPU的消耗就非常大。既然如此,就更改鎖策略,升級成重量級鎖,讓其它的線程都在內(nèi)核里進(jìn)行阻塞等待(這意味著線程要暫時(shí)放棄 CPU 資源,由內(nèi)核進(jìn)行后續(xù)調(diào)度)。

(PS:目前的主流操作系統(tǒng)如 windows,Linux,調(diào)度的開銷都是很大的。系統(tǒng)不承諾能在 xx 時(shí)間內(nèi)一定能完成指定的調(diào)度,極端情況下調(diào)度的開銷可能非常大。

但還存在另外一種實(shí)時(shí)操作系統(tǒng)(例如 vxworks),它能夠以更低的成本完成任務(wù)調(diào)度,但犧牲了更多的其他功能。在如火箭發(fā)射這種對時(shí)間精度比較高的特殊領(lǐng)域就會用到。)

如果競爭進(jìn)一步激烈,自旋不能快速獲取到鎖狀態(tài)。就會膨脹為重量級鎖。

此處的重量級鎖就是指內(nèi)核提供的 mutex 。

  1. 某線程執(zhí)行加鎖操作,先進(jìn)入內(nèi)核態(tài)。
  2. 在內(nèi)核態(tài)判定當(dāng)前鎖是否已經(jīng)被別的線程占用 。
  3. 如果該鎖沒有占用,則加鎖成功,并切換回用戶態(tài)。
  4. 如果該鎖被占用,則加鎖失敗。此時(shí)線程進(jìn)入鎖的等待隊(duì)列并掛起,等待被操作系統(tǒng)喚醒。
  5. 經(jīng)歷了一系列的“滄海桑田”,這個(gè)鎖終于被其他線程釋放了,此時(shí)操作系統(tǒng)也想起了這個(gè)被掛起的線程,于是喚醒這個(gè)線程,并讓它嘗試重新獲取鎖。

二、鎖消除

鎖消除也是“非必要,不加鎖”的一種體現(xiàn)。與鎖升級不同,鎖升級是程序在運(yùn)行階段 JVM 做出的優(yōu)化手段。而鎖消除是在程序編譯階段的優(yōu)化手段。編譯器和 JVM 會檢測當(dāng)前代碼是否是多線程執(zhí)行或是否有必要加鎖。如果無必要,但又把鎖給寫了,那么在編譯的過程中就會自動把鎖去掉。

有些應(yīng)用程序代碼中可能會用到?jīng)]有必要用到的 synchronized。例如 StringBuffer 就是線程安全的,它的每一個(gè)關(guān)鍵方法都加了synchronized關(guān)鍵字:

Java 中 synchronized 的優(yōu)化操作:鎖升級、鎖消除、鎖粗化,# JavaWeb,java,開發(fā)語言,并發(fā)編程,多線程,synchronized

但這里就有一個(gè)問題:如果是在單線程中使用StringBuffer,是不涉及線程安全問題的。這個(gè)時(shí)候其實(shí)就沒必要加鎖。那么這時(shí)編譯器就會出手,發(fā)現(xiàn)synchronized是沒必要加的,就會在編譯階段把synchronized去掉,相當(dāng)于加鎖操作沒有真正被編譯。

StringBuffer sb = new StringBuffer();
sb.append("a");
sb.append("b");
sb.append("c");
sb.append("d");

此時(shí),每個(gè) append 的調(diào)用都會涉及加鎖和解鎖。但如果只是在單線程中執(zhí)行這段代碼,那么其中的這些加鎖解鎖操作是沒有必要的,白白浪費(fèi)了一些資源開銷。

鎖消除整體來說是一個(gè)比較保守的優(yōu)化手段,畢竟編譯器肯定得保證消除的操作是靠譜的。所以只有十拿九穩(wěn)的時(shí)候才會實(shí)施鎖消除,否則仍然會上鎖,這時(shí)就會交給其它的操作策略來對鎖進(jìn)行優(yōu)化(比如上面的鎖升級)。

三、鎖粗化

鎖的粒度指的是 synchronized 代碼塊中包含代碼的多少。代碼越多,粒度越大;代碼越少,粒度越小。

一般我們在寫代碼時(shí),多數(shù)情況下是希望鎖的粒度更小一點(diǎn)。(鎖的粒度小就意味著串行執(zhí)行的代碼更少,并發(fā)執(zhí)行的代碼更多)。如果某個(gè)場景需要頻繁地加鎖解鎖,此時(shí)編譯器就可能把這個(gè)操作優(yōu)化成個(gè)粒度更粗的鎖,即鎖的粗化。

Java 中 synchronized 的優(yōu)化操作:鎖升級、鎖消除、鎖粗化,# JavaWeb,java,開發(fā)語言,并發(fā)編程,多線程,synchronized

實(shí)際開發(fā)過程中使用細(xì)粒度鎖,是期望釋放鎖的時(shí)候其他線程能使用鎖。但是實(shí)際中可能并沒有其他線程來搶占這個(gè)鎖。這種情況 JVM 就會自動把鎖粗化,避免頻繁申請釋放鎖造成不必要的開銷。

舉個(gè)栗子理解鎖粗化

上班時(shí)要向領(lǐng)導(dǎo)匯報(bào)工作。你的領(lǐng)導(dǎo)給你安排了三個(gè)工作:A、B、C。
匯報(bào)方式有:

  1. 先打個(gè)電話,匯報(bào)工作 A 的進(jìn)展,掛了電話;再打個(gè)電話,匯報(bào)工作 B 的進(jìn)展,掛了電話;再打個(gè)電話,匯報(bào)工作C的進(jìn)展,掛了電話。(你給領(lǐng)導(dǎo)打電話,領(lǐng)導(dǎo)接你的電話,領(lǐng)導(dǎo)就干不了別的;別人要給領(lǐng)導(dǎo)打電話,就只能阻塞等待。每次鎖競爭都可能引入一定的等待開銷,此時(shí)整體的效率可能反而更低。)
  2. 打個(gè)電話,一口氣匯報(bào) 工作 A,工作B,工作 C,掛了電話。

顯然第二種方式是更加高效的。

可見,synchronized 的策略是比較復(fù)雜的,它是一個(gè)很“智能”的鎖。文章來源地址http://www.zghlxwxcb.cn/news/detail-596739.html

到了這里,關(guān)于Java 中 synchronized 的優(yōu)化操作:鎖升級、鎖消除、鎖粗化的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Synchronized與鎖升級

    Synchronized與鎖升級

    目錄 1.先從阿里及其他大廠面試題說起 2.路線總綱 3.Synchronized的性能變化? 4.Synchronized鎖種類及升級步驟 4.1多線程訪問情況:3種 4.2升級流程 4.3無鎖 4.4偏向鎖 4.5輕量級鎖 4.6重量級鎖 4.7總結(jié) 5.鎖消除和鎖粗化 1.談?wù)勀銓ynchronized的理解 2.Synchronized的鎖升級 3.線程池幾個(gè)參數(shù)說

    2024年02月01日
    瀏覽(18)
  • 并發(fā)編程11:Synchronized與鎖升級

    并發(fā)編程11:Synchronized與鎖升級

    談?wù)勀銓ynchronized的理解 Sychronized的鎖升級你聊聊 Synchronized實(shí)現(xiàn)原理,monitor對象什么時(shí)候生成的?知道m(xù)onitor的monitorenter和monitorexit這兩個(gè)是怎么保證同步的嘛?或者說這兩個(gè)操作計(jì)算機(jī)底層是如何執(zhí)行的 偏向鎖和輕量級鎖有什么區(qū)別 Java5以前,只有Synchronized,這個(gè)是操作系

    2024年02月04日
    瀏覽(26)
  • 【JVM】synchronized鎖升級的過程

    目錄 如何從無鎖狀態(tài)到偏向鎖狀態(tài): 偏向鎖升級為輕量級鎖: 輕量級鎖到自旋鎖的狀態(tài): 自旋鎖升級為重量級鎖: 下面是自旋鎖升級到重量級鎖的過程: 重量級鎖的特點(diǎn)如下: synchronized鎖分為三種狀態(tài)——偏向鎖、輕量級鎖、重量級鎖 ????????當(dāng)一個(gè)線程訪問被syn

    2024年02月09日
    瀏覽(16)
  • 多線程JUC 第2季 synchronized鎖升級過程

    多線程JUC 第2季 synchronized鎖升級過程

    用鎖能夠?qū)崿F(xiàn)數(shù)據(jù)的安全,但是會帶來性能下降。Synchronized是一個(gè)重量級鎖,鎖的升級過程: 無鎖-偏向鎖-輕量級鎖-重量級鎖。 高并發(fā)時(shí),同步調(diào)用應(yīng)盡量考慮鎖的性能損耗,能用無鎖數(shù)據(jù)結(jié)構(gòu),就不要用鎖,能用區(qū)塊不要用鎖住整個(gè)方法體;能有對象鎖,就不要用類鎖。

    2024年02月09日
    瀏覽(24)
  • 【Java練習(xí)題匯總】《第一行代碼JAVA》多線程篇,匯總Java練習(xí)題——線程及多線程概念、Thread 類及 Runnable 接口、線程狀態(tài)、synchronized同步操作...

    【Java練習(xí)題匯總】《第一行代碼JAVA》多線程篇,匯總Java練習(xí)題——線程及多線程概念、Thread 類及 Runnable 接口、線程狀態(tài)、synchronized同步操作...

    一、填空題 Java 多線程可以依靠________ 、________ 和________ 三種方式實(shí)現(xiàn)。 多個(gè)線程操作同一資源的時(shí)候需要注意________,依靠________ 實(shí)現(xiàn),實(shí)現(xiàn)手段是:________ 和________,過多的使用,則會出現(xiàn)________ 問題。 Java 程序運(yùn)行時(shí),至少啟動________ 個(gè)線程,分別是________ 和_

    2024年02月16日
    瀏覽(24)
  • Golang編譯優(yōu)化——公共子表達(dá)式消除

    Golang編譯優(yōu)化——公共子表達(dá)式消除

    公共子表達(dá)式消除(Common Subexpression Elimination,CSE)也有書上稱為冗余表達(dá)式消除,旨在減少程序中重復(fù)計(jì)算相同表達(dá)式的次數(shù),從而提高程序的執(zhí)行效率。 在程序中,如果同一個(gè)表達(dá)式在不同的地方多次出現(xiàn)并且具有相同的輸入,則這個(gè)表達(dá)式就是一個(gè)公共子表達(dá)式。公共

    2024年04月28日
    瀏覽(22)
  • Synchronized同步鎖的優(yōu)化方法 待完工

    Synchronized同步鎖的優(yōu)化方法 待完工

    在并發(fā)編程中,多個(gè)線程訪問同一個(gè)共享資源時(shí),我們必須考慮如何維護(hù)數(shù)據(jù)的原子性 。在 JDK1.5 之前,Java 是依靠 Synchronized 實(shí)現(xiàn)鎖功能來做到這點(diǎn)的。Synchronized 是 JVM 實(shí)現(xiàn)的一種內(nèi)置鎖,鎖的獲取和釋放是由 JVM 隱式實(shí)現(xiàn)。 到了 JDK1.5 版本,并發(fā)包中新增了 Lock 接口

    2024年02月14日
    瀏覽(28)
  • 【操作系統(tǒng)】死鎖問題---死鎖的消除方法

    【操作系統(tǒng)】死鎖問題---死鎖的消除方法

    本文章將主要解釋死鎖的消除方法 一、死鎖的概念 ? ? ? ? 這是《操作系統(tǒng)》對于死鎖的定義: 有并發(fā)進(jìn)程P1,P2,…Pn,它們共享資源R1,R2,…Rm (n0,m0, n=m)。其中,每個(gè)Pi(1≤i≤n)擁有資源Rj(1≤j ≤m),直到不再有剩余資源。同時(shí),各Pi又在不釋放Rj的前提下要求Rk(k≠j,1≤k ≤m),

    2024年02月15日
    瀏覽(18)
  • 【JavaEE初階】多線程進(jìn)階(五)常見鎖策略 CAS synchronized優(yōu)化原理

    【JavaEE初階】多線程進(jìn)階(五)常見鎖策略 CAS synchronized優(yōu)化原理

    樂觀鎖:預(yù)測鎖競爭不是很激烈。 悲觀鎖:預(yù)測鎖競爭會很激烈。 以上定義并不是絕對的,具體看預(yù)測鎖競爭激烈程度的結(jié)論。 輕量級鎖加鎖解鎖開銷比較小,效率更高。 重量級鎖加鎖解鎖開銷比較大,效率更低。 多數(shù)情況下,樂觀鎖也是一個(gè)輕量級鎖。 多數(shù)情況下,悲

    2024年02月03日
    瀏覽(31)
  • java操作rabbitmq實(shí)現(xiàn)簡單的消息發(fā)送(socket編程的升級)

    準(zhǔn)備: 1.下載rabbitmq并搭建環(huán)境(和python那篇一樣:http://www.cnblogs.com/g177w/p/8176797.html) 2.下載支持的jar包(http://repo1.maven.org/maven2/com/rabbitmq/amqp-client) 生產(chǎn)者方(Productor.java): View Code 消費(fèi)者方(Consummer.java):

    2023年04月08日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包