成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

一文讓你讀懂Synchronized底層實(shí)現(xiàn),秒殺面試官-創(chuàng)新互聯(lián)

本文為死磕Synchronized底層實(shí)現(xiàn)第三篇文章,內(nèi)容為輕量級(jí)鎖實(shí)現(xiàn)。

公司主營(yíng)業(yè)務(wù):成都做網(wǎng)站、成都網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶(hù)真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶(hù)帶來(lái)驚喜。創(chuàng)新互聯(lián)推出紅山免費(fèi)做網(wǎng)站回饋大家。

輕量級(jí)鎖并不復(fù)雜,其中很多內(nèi)容在偏向鎖一文中已提及過(guò),與本文內(nèi)容會(huì)有部分重疊。

另外輕量級(jí)鎖的背景和基本流程在概論中已有講解。強(qiáng)烈建議在看過(guò)兩篇文章的基礎(chǔ)下閱讀本文。

本系列文章將對(duì)HotSpot的synchronized鎖實(shí)現(xiàn)進(jìn)行全面分析,內(nèi)容包括偏向鎖、輕量級(jí)鎖、重量級(jí)鎖的加鎖、解鎖、鎖升級(jí)流程的原理及源碼分析,希望給在研究synchronized路上的同學(xué)一些幫助。

本文分為兩個(gè)部分:

1.輕量級(jí)鎖獲取流程

2.輕量級(jí)鎖釋放流程

本人看的JVM版本是jdk8u。

輕量級(jí)鎖獲取流程

下面開(kāi)始輕量級(jí)鎖獲取流程分析,代碼在bytecodeInterpreter.cpp#1816。

CASE(_monitorenter):?{
??oop?lockee?=?STACK_OBJECT(-1);
??...
??if?(entry?!=?NULL)?{
???...
???//?上面省略的代碼中如果CAS操作失敗也會(huì)調(diào)用到InterpreterRuntime::monitorenter

????//?traditional?lightweight?locking
????if?(!success)?{
??????//?構(gòu)建一個(gè)無(wú)鎖狀態(tài)的Displaced?Mark?Word
??????markOop?displaced?=?lockee->mark()->set_unlocked();
??????//?設(shè)置到Lock?Record中去
??????entry->lock()->set_displaced_header(displaced);
??????bool?call_vm?=?UseHeavyMonitors;
??????if?(call_vm?||?Atomic::cmpxchg_ptr(entry,?lockee->mark_addr(),?displaced)?!=?displaced)?{
????????//?如果CAS替換不成功,代表鎖對(duì)象不是無(wú)鎖狀態(tài),這時(shí)候判斷下是不是鎖重入
????????//?Is?it?simple?recursive?case?
????????if?(!call_vm?&&?THREAD->is_lock_owned((address)?displaced->clear_lock_bits()))?{
??????????entry->lock()->set_displaced_header(NULL);
????????}?else?{
??????????//?CAS操作失敗則調(diào)用monitorenter
??????????CALL_VM(InterpreterRuntime::monitorenter(THREAD,?entry),?handle_exception);
????????}
??????}
????}
????UPDATE_PC_AND_TOS_AND_CONTINUE(1,?-1);
??}?else?{
????istate->set_msg(more_monitors);
????UPDATE_PC_AND_RETURN(0);?//?Re-execute
??}
}

如果鎖對(duì)象不是偏向模式或已經(jīng)偏向其他線程,則successfalse。這時(shí)候會(huì)構(gòu)建一個(gè)無(wú)鎖狀態(tài)的mark word設(shè)置到Lock Record中去,我們稱(chēng)Lock Record中存儲(chǔ)對(duì)象mark word的字段叫Displaced Mark Word。

如果當(dāng)前鎖的狀態(tài)不是無(wú)鎖狀態(tài),則CAS失敗。如果這是一次鎖重入,那直接將Lock Record的?Displaced Mark Word設(shè)置為null。

我們看個(gè)demo,在該demo中重復(fù)3次獲得鎖,

synchronized(obj){
????synchronized(obj){
????	synchronized(obj){
????	}
????}
}

假設(shè)鎖的狀態(tài)是輕量級(jí)鎖,下圖反應(yīng)了mark word和線程棧中Lock Record的狀態(tài),可以看到右邊線程棧中包含3個(gè)指向當(dāng)前鎖對(duì)象的Lock Record。其中棧中最高位的Lock Record為第一次獲取鎖時(shí)分配的。其Displaced Mark word的值為鎖對(duì)象的加鎖前的mark word,之后的鎖重入會(huì)在線程棧中分配一個(gè)Displaced Mark wordnullLock Record。

一文讓你讀懂Synchronized底層實(shí)現(xiàn),秒殺面試官

為什么JVM選擇在線程棧中添加Displaced Mark word為null的Lock Record來(lái)表示重入計(jì)數(shù)呢?首先鎖重入次數(shù)是一定要記錄下來(lái)的,因?yàn)槊看谓怄i都需要對(duì)應(yīng)一次加鎖,解鎖次數(shù)等于加鎖次數(shù)時(shí),該鎖才真正的被釋放,也就是在解鎖時(shí)需要用到說(shuō)鎖重入次數(shù)的。一個(gè)簡(jiǎn)單的方案是將鎖重入次數(shù)記錄在對(duì)象頭的mark word中,但mark word的大小是有限的,已經(jīng)存放不下該信息了。另一個(gè)方案是只創(chuàng)建一個(gè)Lock Record并在其中記錄重入次數(shù),Hotspot沒(méi)有這樣做的原因我猜是考慮到效率有影響:每次重入獲得鎖都需要遍歷該線程的棧找到對(duì)應(yīng)的Lock Record,然后修改它的值。

所以最終Hotspot選擇每次獲得鎖都添加一個(gè)Lock Record來(lái)表示鎖的重入。

接下來(lái)看看InterpreterRuntime::monitorenter方法

IRT_ENTRY_NO_ASYNC(void,?InterpreterRuntime::monitorenter(JavaThread*?thread,?BasicObjectLock*?elem))
??...
??Handle?h_obj(thread,?elem->obj());
??assert(Universe::heap()->is_in_reserved_or_null(h_obj()),
?????????"must?be?NULL?or?an?object");
??if?(UseBiasedLocking)?{
????//?Retry?fast?entry?if?bias?is?revoked?to?avoid?unnecessary?inflation
????ObjectSynchronizer::fast_enter(h_obj,?elem->lock(),?true,?CHECK);
??}?else?{
????ObjectSynchronizer::slow_enter(h_obj,?elem->lock(),?CHECK);
??}
??...
IRT_END

fast_enter的流程在偏向鎖一文已經(jīng)分析過(guò),如果當(dāng)前是偏向模式且偏向的線程還在使用鎖,那會(huì)將鎖的mark word改為輕量級(jí)鎖的狀態(tài),同時(shí)會(huì)將偏向的線程棧中的Lock Record修改為輕量級(jí)鎖對(duì)應(yīng)的形式。代碼位置在biasedLocking.cpp#212。

//?線程還存活則遍歷線程棧中所有的Lock?Record
??GrowableArray<MonitorInfo*>*?cached_monitor_info?=?get_or_compute_monitor_info(biased_thread);
??BasicLock*?highest_lock?=?NULL;
??for?(int?i?=?0;?i?<?cached_monitor_info->length();?i++)?{
????MonitorInfo*?mon_info?=?cached_monitor_info->at(i);
????//?如果能找到對(duì)應(yīng)的Lock?Record說(shuō)明偏向的線程還在執(zhí)行同步代碼塊中的代碼
????if?(mon_info->owner()?==?obj)?{
??????...
??????//?需要升級(jí)為輕量級(jí)鎖,直接修改偏向線程棧中的Lock?Record。為了處理鎖重入的case,在這里將Lock?Record的Displaced?Mark?Word設(shè)置為null,第一個(gè)Lock?Record會(huì)在下面的代碼中再處理
??????markOop?mark?=?markOopDesc::encode((BasicLock*)?NULL);
??????highest_lock?=?mon_info->lock();
??????highest_lock->set_displaced_header(mark);
????}?else?{
??????...
????}
??}
??if?(highest_lock?!=?NULL)?{
????//?修改第一個(gè)Lock?Record為無(wú)鎖狀態(tài),然后將obj的mark?word設(shè)置為指向該Lock?Record的指針
????highest_lock->set_displaced_header(unbiased_prototype);
????obj->release_set_mark(markOopDesc::encode(highest_lock));
????...
??}?else?{
????...
??}

我們看slow_enter的流程。

void?ObjectSynchronizer::slow_enter(Handle?obj,?BasicLock*?lock,?TRAPS)?{
??markOop?mark?=?obj->mark();
??assert(!mark->has_bias_pattern(),?"should?not?see?bias?pattern?here");
??//?如果是無(wú)鎖狀態(tài)
??if?(mark->is_neutral())?{
????//設(shè)置Displaced?Mark?Word并替換對(duì)象頭的mark?word
????lock->set_displaced_header(mark);
????if?(mark?==?(markOop)?Atomic::cmpxchg_ptr(lock,?obj()->mark_addr(),?mark))?{
??????TEVENT?(slow_enter:?release?stacklock)?;
??????return?;
????}
??}?else
??if?(mark->has_locker()?&&?THREAD->is_lock_owned((address)mark->locker()))?{
????assert(lock?!=?mark->locker(),?"must?not?re-lock?the?same?lock");
????assert(lock?!=?(BasicLock*)obj->mark(),?"don't?relock?with?same?BasicLock");
????//?如果是重入,則設(shè)置Displaced?Mark?Word為null
????lock->set_displaced_header(NULL);
????return;
??}

??...
??//?走到這一步說(shuō)明已經(jīng)是存在多個(gè)線程競(jìng)爭(zhēng)鎖了?需要膨脹為重量級(jí)鎖
??lock->set_displaced_header(markOopDesc::unused_mark());
??ObjectSynchronizer::inflate(THREAD,?obj())->enter(THREAD);
}

輕量級(jí)鎖釋放流程

CASE(_monitorexit):?{
??oop?lockee?=?STACK_OBJECT(-1);
??CHECK_NULL(lockee);
??//?derefing's?lockee?ought?to?provoke?implicit?null?check
??//?find?our?monitor?slot
??BasicObjectLock*?limit?=?istate->monitor_base();
??BasicObjectLock*?most_recent?=?(BasicObjectLock*)?istate->stack_base();
??//?從低往高遍歷棧的Lock?Record
??while?(most_recent?!=?limit?)?{
????//?如果Lock?Record關(guān)聯(lián)的是該鎖對(duì)象
????if?((most_recent)->obj()?==?lockee)?{
??????BasicLock*?lock?=?most_recent->lock();
??????markOop?header?=?lock->displaced_header();
??????//?釋放Lock?Record
??????most_recent->set_obj(NULL);
??????//?如果是偏向模式,僅僅釋放Lock?Record就好了。否則要走輕量級(jí)鎖or重量級(jí)鎖的釋放流程
??????if?(!lockee->mark()->has_bias_pattern())?{
????????bool?call_vm?=?UseHeavyMonitors;
????????//?header!=NULL說(shuō)明不是重入,則需要將Displaced?Mark?Word?CAS到對(duì)象頭的Mark?Word
????????if?(header?!=?NULL?||?call_vm)?{
??????????if?(call_vm?||?Atomic::cmpxchg_ptr(header,?lockee->mark_addr(),?lock)?!=?lock)?{
????????????//?CAS失敗或者是重量級(jí)鎖則會(huì)走到這里,先將obj還原,然后調(diào)用monitorexit方法
????????????most_recent->set_obj(lockee);
????????????CALL_VM(InterpreterRuntime::monitorexit(THREAD,?most_recent),?handle_exception);
??????????}
????????}
??????}
??????//執(zhí)行下一條命令
??????UPDATE_PC_AND_TOS_AND_CONTINUE(1,?-1);
????}
????//處理下一條Lock?Record
????most_recent++;
??}
??//?Need?to?throw?illegal?monitor?state?exception
??CALL_VM(InterpreterRuntime::throw_illegal_monitor_state_exception(THREAD),?handle_exception);
??ShouldNotReachHere();
}

輕量級(jí)鎖釋放時(shí)需要將Displaced Mark Word替換到對(duì)象頭的mark word中。如果CAS失敗或者是重量級(jí)鎖則進(jìn)入到InterpreterRuntime::monitorexit方法中。

//%note?monitor_1
IRT_ENTRY_NO_ASYNC(void,?InterpreterRuntime::monitorexit(JavaThread*?thread,?BasicObjectLock*?elem))
?
??Handle?h_obj(thread,?elem->obj());
??...
??ObjectSynchronizer::slow_exit(h_obj(),?elem->lock(),?thread);
??//?Free?entry.?This?must?be?done?here,?since?a?pending?exception?might?be?installed?on
??//釋放Lock?Record
??elem->set_obj(NULL);
??...
IRT_END

monitorexit調(diào)用完slow_exit方法后,就釋放Lock Record

void?ObjectSynchronizer::slow_exit(oop?object,?BasicLock*?lock,?TRAPS)?{
??fast_exit?(object,?lock,?THREAD)?;
}
void?ObjectSynchronizer::fast_exit(oop?object,?BasicLock*?lock,?TRAPS)?{
??...
??markOop?dhw?=?lock->displaced_header();
??markOop?mark?;
??if?(dhw?==?NULL)?{
?????//?重入鎖,什么也不做
???	?...
?????return?;
??}

??mark?=?object->mark()?;

??//?如果是mark?word==Displaced?Mark?Word即輕量級(jí)鎖,CAS替換對(duì)象頭的mark?word
??if?(mark?==?(markOop)?lock)?{
?????assert?(dhw->is_neutral(),?"invariant")?;
?????if?((markOop)?Atomic::cmpxchg_ptr?(dhw,?object->mark_addr(),?mark)?==?mark)?{
????????TEVENT?(fast_exit:?release?stacklock)?;
????????return;
?????}
??}
??//走到這里說(shuō)明是重量級(jí)鎖或者解鎖時(shí)發(fā)生了競(jìng)爭(zhēng),膨脹后調(diào)用重量級(jí)鎖的exit方法。
??ObjectSynchronizer::inflate(THREAD,?object)->exit?(true,?THREAD)?;
}

該方法中先判斷是不是輕量級(jí)鎖,如果是輕量級(jí)鎖則將替換mark word,否則膨脹為重量級(jí)鎖并調(diào)用exit方法,相關(guān)邏輯將在重量級(jí)鎖的文章中講解。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。

當(dāng)前文章:一文讓你讀懂Synchronized底層實(shí)現(xiàn),秒殺面試官-創(chuàng)新互聯(lián)
本文來(lái)源:http://jinyejixie.com/article44/digjee.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、搜索引擎優(yōu)化、虛擬主機(jī)、Google、網(wǎng)站制作服務(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)

外貿(mào)網(wǎng)站建設(shè)
白城市| 黄陵县| 银川市| 洛浦县| 肥乡县| 合阳县| 临沭县| 宜兰市| 通州市| 济南市| 墨玉县| 平乡县| 墨玉县| 额敏县| 谢通门县| 淄博市| 额敏县| 东乡| 北安市| 平乡县| 绥阳县| 谷城县| 张家港市| 徐汇区| 桂阳县| 文安县| 久治县| 玉环县| 凭祥市| 山东| 玉山县| 昌宁县| 防城港市| 奉化市| 章丘市| 德江县| 曲阜市| 临潭县| 涞源县| 平谷区| 沐川县|