本篇內(nèi)容主要講解“Synchronized的原理介紹”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Synchronized的原理介紹”吧!
創(chuàng)新互聯(lián)建站是一家專(zhuān)業(yè)提供樂(lè)業(yè)企業(yè)網(wǎng)站建設(shè),專(zhuān)注與成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、H5開(kāi)發(fā)、小程序制作等業(yè)務(wù)。10年已為樂(lè)業(yè)眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專(zhuān)業(yè)的建站公司優(yōu)惠進(jìn)行中。
CAS
全稱(chēng):CompareAndSwap
,故名思意:比較并交換。他的主要思想就是:**我需要對(duì)一個(gè)值進(jìn)行修改,我不會(huì)直接修改,而是將當(dāng)前我認(rèn)為的值和要修改的值傳入,如果此時(shí)內(nèi)存中的確為我認(rèn)為的值,那么就進(jìn)行修改,否則修改失敗。**他的思想是一種樂(lè)觀鎖的思想。
一張圖解釋他的工作流程:
知道了它的工作原理,我們來(lái)聽(tīng)一個(gè)場(chǎng)景:現(xiàn)在有一個(gè)int
類(lèi)型的數(shù)字它等于1,存在三個(gè)線程需要對(duì)其進(jìn)行自增操作。
一般來(lái)說(shuō),我們認(rèn)為的操作步驟是這樣:線程從主內(nèi)存中讀取這個(gè)變量,到自己的工作空間中,然后執(zhí)行變量自增,然后回寫(xiě)主內(nèi)存,但這樣在多線程狀態(tài)下會(huì)存在安全問(wèn)題。而如果我們保證變量的安全性,常用的做法是ThreadLocal
或者直接加鎖。(對(duì)ThreadLocal
不了解的兄弟,看我這篇文章一文讀懂ThreadLocal設(shè)計(jì)思想)
這個(gè)時(shí)候我們思考一下,如果使用我們上面的CAS
進(jìn)行對(duì)值的修改,我們需要如何操作。
首先,我們需要將當(dāng)前線程認(rèn)為的值傳入,然后將想要修改的值傳入。如果此時(shí)內(nèi)存中的值和我們的期望值相等,進(jìn)行修改,否則修改失敗。這樣是不是解決了一個(gè)多線程修改的問(wèn)題,而且它沒(méi)有使用到操作系統(tǒng)提供的鎖。
上面的流程其實(shí)就是類(lèi)AtomicInteger
執(zhí)行自增操作的底層實(shí)現(xiàn),它保證了一個(gè)操作的原子性。我們來(lái)看一下源碼。
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { //從內(nèi)存中讀取最新值 var5 = this.getIntVolatile(var1, var2); //修改 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
實(shí)現(xiàn)CAS
使用到了Unsafe
類(lèi),看它的名字就知道不安全,所以JDK
不建議我們使用。對(duì)比我們上面多個(gè)線程執(zhí)行一個(gè)變量的修改流程,這個(gè)類(lèi)的操作僅僅增加了一個(gè)自旋,它在不斷獲取內(nèi)存中的最新值,然后執(zhí)行自增操作。
可能有兄弟說(shuō)了,那getIntVolatile
和compareAndSwapInt
操作如何保證原子性。
對(duì)于getIntVolatile
來(lái)說(shuō),讀取內(nèi)存中的地址,本來(lái)就一部操作,原子性顯而易見(jiàn)。
對(duì)于compareAndSwapInt
來(lái)說(shuō),它的原子性由CPU
保證,通過(guò)一系列的CPU
指令實(shí)現(xiàn),其C++
底層是依賴(lài)于Atomic::cmpxchg_ptr
實(shí)現(xiàn)的
到這里CAS
講完了,不過(guò)其中還有一個(gè)ABA
問(wèn)題,有興趣可以去了解我的這篇文章多線程知識(shí)點(diǎn)小節(jié)。里面有詳細(xì)的講解。
我們通過(guò)CAS
可以保證了操作的原子性,那么我們需要考慮一個(gè)東西,鎖是怎么實(shí)現(xiàn)的。對(duì)比生活中的case
,我們通過(guò)一組密碼或者一把鑰匙實(shí)現(xiàn)了一把鎖,同樣在計(jì)算機(jī)中也通過(guò)一個(gè)鑰匙即synchronized
代碼塊使用的鎖對(duì)象。
那其他線程如何判斷當(dāng)前資源已經(jīng)被占有了呢?
在計(jì)算機(jī)中的實(shí)現(xiàn),往往是通過(guò)對(duì)一個(gè)變量的判斷來(lái)實(shí)現(xiàn),無(wú)鎖狀態(tài)為0
,有鎖狀態(tài)為1
等等來(lái)判斷這個(gè)資源是否被加鎖了,當(dāng)一個(gè)線程釋放鎖時(shí)僅僅需要將這個(gè)變量值更改為0,代表無(wú)鎖。
我們僅僅需要保證在進(jìn)行變量修改時(shí)的原子性即可,而剛剛的CAS
剛好可以解決這個(gè)問(wèn)題
至于那個(gè)鎖變量存儲(chǔ)在哪里這個(gè)問(wèn)題,就是下面的內(nèi)容了,對(duì)象的內(nèi)存布局
各位兄弟們,應(yīng)該都清楚,我們創(chuàng)建的對(duì)象都是被存放到堆中的,最后我們獲得到的是一個(gè)對(duì)象的引用指針。那么有一個(gè)問(wèn)題就會(huì)誕生了,JVM
創(chuàng)建的對(duì)象的時(shí)候,開(kāi)辟了一塊空間,那這個(gè)空間里都有什么東西?這個(gè)就是我們這個(gè)點(diǎn)的內(nèi)容。
先來(lái)結(jié)論:Java
中存在兩種類(lèi)型的對(duì)象,一種是普通對(duì)象,另一種是數(shù)組
對(duì)象內(nèi)存布局
我們來(lái)一個(gè)一個(gè)解釋其含義。
**白話版:**對(duì)象頭中包含又兩個(gè)字段,Mark Word
主要存儲(chǔ)改對(duì)象的鎖信息,GC
信息等等(鎖升級(jí)的實(shí)現(xiàn))。而其中的Klass Point
代表的是一個(gè)類(lèi)指針,它指向了方法區(qū)中類(lèi)的定義和結(jié)構(gòu)信息。而Instance Data
代表的就是類(lèi)的成員變量。在我們剛剛學(xué)習(xí)Java
基礎(chǔ)的時(shí)候,都聽(tīng)過(guò)老師講過(guò),對(duì)象的非靜態(tài)成員屬性都會(huì)被存放在堆中,這個(gè)就是對(duì)象的Instance Data
。相對(duì)于對(duì)象而言,數(shù)組額外添加了一個(gè)數(shù)組長(zhǎng)度的屬性
最后一個(gè)對(duì)其數(shù)據(jù)是什么?
我們拿一個(gè)場(chǎng)景來(lái)展示這個(gè)原因:**想像一下,你和女朋友周末打算出去玩,女朋友讓你給她帶上口紅,那么這個(gè)時(shí)候你僅僅會(huì)帶上口紅嘛?當(dāng)然不是,而是將所有的必用品統(tǒng)統(tǒng)帶上,以防剛一出門(mén)就得回家拿東西?。?!**這種行為叫啥?未雨綢繆,沒(méi)錯(cuò),暖男行為。還不懂?再來(lái)一個(gè)案例。你準(zhǔn)備創(chuàng)業(yè)了,資金非常充足,你需要注冊(cè)一個(gè)域名,你僅僅注冊(cè)一個(gè)嘛?不,而是將所有相關(guān)的都注冊(cè)了,防止以后大價(jià)錢(qián)買(mǎi)域名。一個(gè)道理。
而對(duì)于CPU
而言,它在進(jìn)行計(jì)算處理數(shù)據(jù)的時(shí)候,不可能需要什么拿什么吧,那對(duì)其性能損耗非常嚴(yán)重。所以有一個(gè)協(xié)議,CPU
在讀取數(shù)據(jù)的時(shí)候,不僅僅只拿需要的數(shù)據(jù),而是獲取一行的數(shù)據(jù),這就是緩存行,而一行是64個(gè)字節(jié)。
所以呢?通過(guò)這個(gè)特性可以玩一些詭異的花樣,比如下面的代碼。
public class CacheLine { private volatile Long l1 , l2; }
我們給一個(gè)場(chǎng)景:兩個(gè)線程t1和t2
分別操作l1
和l2
,那么當(dāng)t1
對(duì)l1
做了修改以后,l2
需不需要重新讀取主內(nèi)存種值。答案是一定,根據(jù)我們上面對(duì)于緩存行的理解,l1和l2
必然位于同一個(gè)緩存行中,根據(jù)緩存一致性協(xié)議,當(dāng)數(shù)據(jù)被修改以后,其他CPU
需要重新重主內(nèi)存中讀取數(shù)據(jù)。這就引發(fā)了偽共享的問(wèn)題
那么為什么對(duì)象頭要求會(huì)存在一個(gè)對(duì)其數(shù)據(jù)呢?
HotSpot
虛擬機(jī)要求每一個(gè)對(duì)象的內(nèi)存大小必須保證為8字節(jié)的整數(shù)倍,所以對(duì)于不是8字節(jié)的進(jìn)行了對(duì)其補(bǔ)充。其原因也是因?yàn)榫彺嫘械脑?/p>
對(duì)象=對(duì)象頭+實(shí)例數(shù)據(jù)
我們?cè)谇懊媪牧艘幌?,?jì)算機(jī)中的鎖的實(shí)現(xiàn)思路和對(duì)象在內(nèi)存中的布局,接下來(lái)我們來(lái)聊一下它的具體鎖實(shí)現(xiàn),為對(duì)象加鎖使用的是對(duì)象內(nèi)存模型中的對(duì)象頭,通過(guò)對(duì)其鎖標(biāo)志位和偏向鎖標(biāo)志位的修改實(shí)現(xiàn)對(duì)資源的獨(dú)占即加鎖操作。接下來(lái)我們看一下它的內(nèi)存結(jié)構(gòu)圖。
上圖就是對(duì)象頭在內(nèi)存中的表現(xiàn)(64位),JVM
通過(guò)對(duì)對(duì)象頭中的鎖標(biāo)志位和偏向鎖位的修改實(shí)現(xiàn)“無(wú)鎖”。
對(duì)于無(wú)鎖這個(gè)概念來(lái)說(shuō),在1.6
之前,即所有的對(duì)象,被創(chuàng)建了以后都處于無(wú)鎖狀態(tài),而在1.6
之后,偏向鎖被開(kāi)啟,對(duì)象在經(jīng)歷過(guò)幾秒的時(shí)候(4~5s)以后,自動(dòng)升級(jí)為當(dāng)前線程的偏向鎖。(無(wú)論經(jīng)沒(méi)經(jīng)過(guò)synchronized
)。
我們來(lái)驗(yàn)證一下,通過(guò)jol-core
工具打印其內(nèi)存布局。注:該工具打印出來(lái)的數(shù)據(jù)信息是反的,即最后幾位在前面,通過(guò)下面的案例可以看到
場(chǎng)景:創(chuàng)建兩個(gè)對(duì)象,一個(gè)在剛開(kāi)始的時(shí)候就創(chuàng)建,另一個(gè)在5
秒之后創(chuàng)建,進(jìn)行對(duì)比其內(nèi)存布局
Object object = new Object(); System.out.println(ClassLayout.parseInstance(object).toPrintable());//此時(shí)處于無(wú)鎖態(tài) try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();} Object o = new Object(); System.out.println("偏向鎖開(kāi)啟"); System.out.println(ClassLayout.parseInstance(o).toPrintable());//五秒以后偏向鎖開(kāi)啟
我們可以看到,線程已開(kāi)啟創(chuàng)建的對(duì)象處于無(wú)鎖態(tài),而在5秒以后創(chuàng)建的線程處于偏向鎖狀態(tài)。
同樣,當(dāng)我們遇到synchronized
塊的時(shí)候,也會(huì)自動(dòng)升級(jí)為偏向鎖,而不是和操作系統(tǒng)申請(qǐng)鎖。
說(shuō)完這個(gè),提一嘴一個(gè)面試題吧。解釋一下什么是無(wú)鎖。
從對(duì)象內(nèi)存結(jié)構(gòu)的角度來(lái)說(shuō),是一個(gè)鎖標(biāo)志位的體現(xiàn);從其語(yǔ)義來(lái)說(shuō),無(wú)鎖這個(gè)比較抽象了,因?yàn)樵谝郧版i的概念往往是與操作系統(tǒng)的鎖息息相關(guān),所以新出現(xiàn)的基于CAS
的偏向鎖,輕量級(jí)鎖等等也被成為無(wú)鎖。而在synchronized
升級(jí)的起點(diǎn)----無(wú)鎖。這個(gè)東西就比較難以解釋?zhuān)荒苷f(shuō)它沒(méi)加鎖。不過(guò)面試的過(guò)程中從對(duì)象內(nèi)存模型中理解可能會(huì)更加舒服一點(diǎn)。
在實(shí)際開(kāi)發(fā)中,往往資源的競(jìng)爭(zhēng)比較少,于是出現(xiàn)了偏向鎖,故名思意,當(dāng)前資源偏向于該線程,認(rèn)為將來(lái)的一切操作均來(lái)自于改線程。下面我們從對(duì)象的內(nèi)存布局下看看偏向鎖
對(duì)象頭描述:偏向鎖標(biāo)志位通過(guò)CAS修改為1,并且存儲(chǔ)該線程的線程指針
當(dāng)發(fā)生了鎖競(jìng)爭(zhēng),其實(shí)也不算鎖競(jìng)爭(zhēng),就是當(dāng)這個(gè)資源被多個(gè)線程使用的時(shí)候,偏向鎖就會(huì)升級(jí)。
在升級(jí)的期間有一個(gè)點(diǎn)-----全局安全點(diǎn),只有處在這個(gè)點(diǎn)的時(shí)候,才會(huì)撤銷(xiāo)偏向鎖。
全局安全點(diǎn)-----類(lèi)似于CMS
的stop the world
,保證這個(gè)時(shí)候沒(méi)有任何線程在操作這個(gè)資源,這個(gè)時(shí)間點(diǎn)就叫做全局安全點(diǎn)。
可以通過(guò)XX:BiasedLockingStartupDelay=0
關(guān)閉偏向鎖的延遲,使其立即生效。
通過(guò)XX:-UseBiasedLocking=false
關(guān)閉偏向鎖。
在聊輕量級(jí)鎖的時(shí)候,我們需要搞明白這幾個(gè)問(wèn)題。什么是輕量級(jí)鎖,什么重量級(jí)鎖?,為什么就重量了,為什么就輕量了?
輕量級(jí)和重量級(jí)的標(biāo)準(zhǔn)是依靠于操作系統(tǒng)作為標(biāo)準(zhǔn)判斷的,在進(jìn)行操作的時(shí)候你有沒(méi)有調(diào)用過(guò)操作系統(tǒng)的鎖資源,如果有就是重量級(jí),如果沒(méi)有就是輕量級(jí)
接下來(lái)我們看一下輕量級(jí)鎖的實(shí)現(xiàn)。
線程獲取鎖,判斷當(dāng)前線程是否處于無(wú)鎖或者偏向鎖的狀態(tài),如果是,通過(guò)CAS
復(fù)制當(dāng)前對(duì)象的對(duì)象頭到Lock Recoder
放置到當(dāng)前棧幀中(對(duì)于JVM
內(nèi)存模型不清楚的兄弟,看這里入門(mén)JVM看這一篇就夠了
通過(guò)CAS
將當(dāng)前對(duì)象的對(duì)象頭設(shè)置為棧幀中的Lock Recoder
,并且將鎖標(biāo)志位設(shè)置為00
如果修改失敗,則判斷當(dāng)前棧幀中的線程是否為自己,如果是自己直接獲取鎖,如果不是升級(jí)為重量級(jí)鎖,后面的線程阻塞
我們?cè)谏厦嫣岬搅艘粋€(gè)Lock Recoder
,這個(gè)東東是用來(lái)保存當(dāng)前對(duì)象的對(duì)象頭中的數(shù)據(jù)的,并且此時(shí)在該對(duì)象的對(duì)象頭中保存的數(shù)據(jù)成為了當(dāng)前Lock Recoder
的指針
我們看一個(gè)代碼模擬案例,
public class QingLock { public static void main(String[] args) { try { //睡覺(jué)5秒,開(kāi)啟偏向鎖,可以使用JVM參數(shù) TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();} A o = new A(); //讓線程交替執(zhí)行 CountDownLatch countDownLatch = new CountDownLatch(1); new Thread(()->{ o.test(); countDownLatch.countDown(); },"1").start(); new Thread(()->{ try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } o.test(); },"2").start(); } } class A{ private Object object = new Object(); public void test(){ System.out.println("為進(jìn)入同步代碼塊*****"); System.out.println(ClassLayout.parseInstance(object).toPrintable()); System.out.println("進(jìn)入同步代碼塊******"); for (int i = 0; i < 5; i++) { synchronized (object){ System.out.println(ClassLayout.parseInstance(object).toPrintable()); } } } }
運(yùn)行結(jié)果為兩個(gè)線程交替前后
輕量級(jí)鎖強(qiáng)調(diào)的是線程交替使用資源,無(wú)論線程的個(gè)數(shù)有幾個(gè),只要沒(méi)有同時(shí)使用就不會(huì)升級(jí)為重量級(jí)鎖
在上面的關(guān)于輕量級(jí)鎖加鎖步驟的講解中,如果線程CAS
修改失敗,則判斷棧幀中的owner
是不是自己,如果不是就失敗升級(jí)為重量級(jí)鎖,而在實(shí)際中,JDK
加入了一種機(jī)制自旋鎖,即修改失敗以后不會(huì)立即升級(jí)而是進(jìn)行自旋,在JDK1.6
之前自旋次數(shù)為10
次,而在1.6
又做了優(yōu)化,改為了自適應(yīng)自旋鎖,由虛擬機(jī)判斷是否需要進(jìn)行自旋,判斷原因有:當(dāng)前線程之前是否獲取到過(guò)鎖,如果沒(méi)有,則認(rèn)為獲取鎖的幾率不大,直接升級(jí),如果有則進(jìn)行自旋獲取鎖。
前面我們談到了無(wú)鎖-->偏向鎖-->輕量級(jí)鎖,現(xiàn)在最后我們來(lái)聊一下重量級(jí)鎖。
這個(gè)鎖在我們開(kāi)發(fā)過(guò)程中很常見(jiàn),線程搶占資源大部分都是同時(shí)的,所以synchronized
會(huì)直接升級(jí)為重量級(jí)鎖。我們來(lái)代碼模擬看一下它的對(duì)象頭的狀況。
代碼模擬
public class WeightLock { public static void main(String[] args) { A a = new A(); for (int i = 0; i < 2; i++) { new Thread(()->{ a.test(); },"線程"+ i).start(); } } }
未進(jìn)入代碼塊之前,兩者均為無(wú)鎖狀態(tài)
開(kāi)始執(zhí)行循環(huán),進(jìn)入代碼塊
在看一眼,對(duì)象頭鎖標(biāo)志位
對(duì)比上圖,可以發(fā)現(xiàn),在線程競(jìng)爭(zhēng)的時(shí)候鎖,已經(jīng)變?yōu)榱酥亓考?jí)鎖。接下來(lái)我們來(lái)看一下重量級(jí)鎖的實(shí)現(xiàn)
我們先從Java
字節(jié)碼分析synchronzied
的底層實(shí)現(xiàn),它的主要實(shí)現(xiàn)邏輯是依賴(lài)于一個(gè)monitor
對(duì)象,當(dāng)前線程執(zhí)行遇到monitorenter
以后,給當(dāng)前對(duì)象的一個(gè)屬性recursions
加一(下面會(huì)詳細(xì)講解),當(dāng)遇到monitorexit
以后該屬性減一,代表釋放鎖。
代碼
Object o = new Object(); synchronized (o){ }
匯編碼
上圖就是上面的四行代碼的匯編碼,我們可以看到synchronized
的底層是兩個(gè)匯編指令
monitoreneter
代表synchronized
塊開(kāi)始
monitorexit
代表synchronized
塊結(jié)束
有兄弟要說(shuō)了為什么會(huì)有兩個(gè)monitorexit
?這也是我曾經(jīng)遇到的一個(gè)面試題
第一個(gè)monitorexit
代表了synchronized
塊正常退出
第二個(gè)monitorexit
代表了synchronized
塊異常退出
很好理解,當(dāng)在synchronized
塊中出現(xiàn)了異常以后,不能當(dāng)前線程一直拿著鎖不讓其他線程使用吧。所以出現(xiàn)了兩個(gè)monitorexit
同步代碼塊理解了,我們?cè)賮?lái)看一下同步方法。
代碼
public static void main(String[] args) { } public synchronized void test01(){ }
匯編碼
我們可以看到,同步方法增加了一個(gè)ACC_SYNCHRONIZED
標(biāo)志,它會(huì)在同步方法執(zhí)行之前調(diào)用monitorenter
,結(jié)束以后調(diào)用monitorexit
指令。
在Java
匯編碼的講解中,我們提到了兩個(gè)指令monitorenter
和monitorexit
,其實(shí)他們是來(lái)源于一個(gè)C++
對(duì)象monitor
,在Java
中每創(chuàng)建一個(gè)對(duì)象的時(shí)候都會(huì)有一個(gè)monitor
對(duì)象被隱式創(chuàng)建,他們和當(dāng)前對(duì)象綁定,用于監(jiān)視當(dāng)前對(duì)象的狀態(tài)。其實(shí)說(shuō)綁定也不算正確,其實(shí)際流程為:線程本身維護(hù)了兩個(gè)MonitorList
列表,分別為空閑(free)和已經(jīng)使用(used),當(dāng)線程遇到同步代碼塊或者同步方法的時(shí)候,會(huì)從空閑列表中申請(qǐng)一個(gè)monitor
使用,如果當(dāng)先線程已經(jīng)沒(méi)有空閑的了,則直接從全局(JVM
)獲取一個(gè)monitor
使用
我們來(lái)看一下C++
對(duì)這個(gè)對(duì)象的描述
ObjectMonitor() { _header = NULL; _count = 0; _waiters = 0, _recursions = 0; // 重入次數(shù) _object = NULL; //存儲(chǔ)該Monitor對(duì)象 _owner = NULL; //擁有該Monitor對(duì)象的對(duì)象 _WaitSet = NULL; //線程等待集合(Waiting) _WaitSetLock = 0 ; _Responsible = NULL ; _succ = NULL ; _cxq = NULL ; //多線程競(jìng)爭(zhēng)時(shí)的單向鏈表 FreeNext = NULL ; _EntryList = NULL ; //阻塞鏈表(Block) _SpinFreq = 0 ; _SpinClock = 0 ; OwnerIsThread = 0 ; _previous_owner_tid = 0; }
線程加鎖模型
加鎖流程:
最新進(jìn)入的線程會(huì)進(jìn)入_cxp
棧中,嘗試獲取鎖,如果當(dāng)前線程獲得鎖就執(zhí)行代碼,如果沒(méi)有獲取到鎖則添加到EntryList
阻塞隊(duì)列中
如果在執(zhí)行的過(guò)程的當(dāng)前線程被掛起(wait
)則被添加到WaitSet
等待隊(duì)列中,等待被喚醒繼續(xù)執(zhí)行
當(dāng)同步代碼塊執(zhí)行完畢以后,從_cxp
或者EntryList
中獲取一個(gè)線程執(zhí)行
monitorenter
加鎖實(shí)現(xiàn)
CAS
修改當(dāng)前monitor
對(duì)象的_owner
為當(dāng)前線程,如果修改成功,執(zhí)行操作;
如果修改失敗,判斷_owner
對(duì)象是否為當(dāng)前線程,如果是則令_recursions
重入次數(shù)加一
如果當(dāng)前實(shí)現(xiàn)是第一次獲取到鎖,則將_recursions
設(shè)置為一
等待鎖釋放
阻塞和獲取鎖實(shí)現(xiàn)
將當(dāng)前線程封裝為一個(gè)node
節(jié)點(diǎn),狀態(tài)設(shè)置為ObjectWaiter::TS_CXQ
將之添加到_cxp
棧中,嘗試獲取鎖,如果獲取失敗,則將當(dāng)前線程掛起,等待喚醒
喚醒以后,從掛起點(diǎn)執(zhí)行剩下的代碼
monitorexit
釋放鎖實(shí)現(xiàn)
讓當(dāng)前線程的_recursions
重入次數(shù)減一,如果當(dāng)前重入次數(shù)為0,則直接退出,喚醒其他線程
到此,相信大家對(duì)“Synchronized的原理介紹”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!
分享標(biāo)題:Synchronized的原理介紹
轉(zhuǎn)載來(lái)源:http://jinyejixie.com/article48/iiesep.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、定制開(kāi)發(fā)、關(guān)鍵詞優(yōu)化、電子商務(wù)、面包屑導(dǎo)航、云服務(wù)器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)