Java同步鎖Synchronized底層源碼和原理剖析(推薦)
1 synchronized場(chǎng)景回顧
目標(biāo):
synchronized回顧(鎖分類–>多線程)
概念
synchronized:是Java中的關(guān)鍵字,是一種同步鎖。
Java中鎖分為以下幾種:
樂(lè)觀鎖、悲觀鎖(syn)
獨(dú)享鎖(syn)、共享鎖
公平鎖、非公平鎖(syn)
互斥鎖(syn)、讀寫鎖
可重入鎖(syn)
分段鎖
synchronized JDK1.6鎖升級(jí)(無(wú)鎖 -> 偏向鎖 (非鎖)-> 輕量級(jí)鎖 -> 重量級(jí)鎖(1.6前都是)【面試常問(wèn)】
tips:
為什么用到鎖?大家肯定會(huì)想到多線程(并發(fā))
接下來(lái),我們一起簡(jiǎn)單回顧下多線程特性
多線程特性回顧(面試常問(wèn))原子性
:指一個(gè)操作或者多個(gè)操作,要么全部執(zhí)行并且執(zhí)行的過(guò)程不會(huì)被任何因素打斷,要么就都不執(zhí)
行可見性
:是指多個(gè)線程訪問(wèn)一個(gè)資源時(shí),該資源的狀態(tài)、值信息等對(duì)于其他線程都是可見的。有序性
:指程序中代碼的執(zhí)行順序 (編譯器會(huì)重排)
原子性實(shí)現(xiàn)回顧
保證了原子性?
com.syn.com.syn.th.SyncAtomicity
package com.syn.com.syn.th; import java.util.concurrent.TimeUnit; /* 目標(biāo):測(cè)試原子性問(wèn)題 1、調(diào)用正常(不加鎖)方法;兩個(gè)線程都可以正常執(zhí)行 2、調(diào)用加鎖方法,只能有一個(gè)線程正常執(zhí)行,其他線程排隊(duì)等候 */ public class SyncAtomicity { public static void main(String[] args) throws InterruptedException { SyncAtomicity syncAtomicity = new SyncAtomicity(); //synchronized修飾實(shí)例方法 //new Thread(()->syncAtomicity.testSYNC()).start(); //new Thread(()->syncAtomicity.testSYNC()).start(); //synchronized修飾靜態(tài)方法 new Thread(() -> SyncAtomicity.testSYNCForStatic()).start(); new Thread(() -> SyncAtomicity.testSYNCForStatic()).start(); //正常方法 //new Thread(() -> syncAtomicity.test()).start(); //new Thread(() -> syncAtomicity.test()).start(); } //加鎖方法 public synchronized void testSYNC() { System.out.println("進(jìn)入testSYNC方法>>>>>>>>>>>>>>>>>>>>>"); try { //模擬方法體尚未執(zhí)行完畢 TimeUnit.HOURS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } //加鎖方法 public synchronized static void testSYNCForStatic() { System.out.println("進(jìn)入testSYNC方法>>>>>>>>>>>>>>>>>>>>>"); try { //模擬方法體尚未執(zhí)行完畢 TimeUnit.HOURS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } //正常方法 public void test() { System.out.println("進(jìn)入test方法>>>>>>>>>>>>>>>>>>>>>"); try { //模擬方法體尚未執(zhí)行完畢 TimeUnit.HOURS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }
總結(jié)
我們發(fā)現(xiàn)在同一時(shí)刻確實(shí)只有一個(gè)線程進(jìn)入,保證了原子性
這是什么原理呢?
2 反匯編尋找鎖實(shí)現(xiàn)原理
目標(biāo) 通過(guò)javap反匯編看一下synchronized到底是怎么加鎖的
com.syn.BTest
public class BTest { private static Object object = new Object(); public synchronized void testMethod() { System.out.println("Hello World -synchronized method "); } public static void main(String[] args) { synchronized (object) { System.out.println("Hello World -synchronized block "); } } }
反匯編后,我們將看到什么?
JDK自帶的一個(gè)工具: javap ,對(duì)字節(jié)碼進(jìn)行反匯編:
//com.syn.BTest javap -v -c BTest.class
反匯編后
解釋
被synchronized修飾的代碼塊,多了兩個(gè)指令
monitorenter、monitorexit
即JVM使用monitorenter和monitorexit兩個(gè)指令實(shí)現(xiàn)同步
解釋
被synchronized修飾的方法;增加 了ACC_SYNCHRONIZED 修飾。會(huì)隱式調(diào)用monitorenter和
monitorexit。
monitorenter原理(重要)
monitorenter首先我們來(lái)看一下JVM規(guī)范中對(duì)于monitorenter的描述
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.monitorenter
翻譯如下:
每一個(gè)對(duì)象都會(huì)和一個(gè)監(jiān)視器monitor關(guān)聯(lián)。
監(jiān)視器被占用時(shí)會(huì)被鎖住,其他線程無(wú)法來(lái)獲取該monitor。
當(dāng)JVM執(zhí)行某個(gè)線程的某個(gè)方法內(nèi)部的monitorenter時(shí),它會(huì)嘗試去獲取當(dāng)前對(duì)象對(duì)應(yīng)的monitor的所有權(quán)。其過(guò)程如下:
- 若monior的進(jìn)入數(shù)為0,線程可以進(jìn)入monitor,并將monitor的進(jìn)入數(shù)置為1。當(dāng)前線程成為
- monitor的owner(所有者)
- 若線程已擁有monitor的所有權(quán),允許它重入monitor,則進(jìn)入monitor的進(jìn)入數(shù)加1
- 若其他線程已經(jīng)占有monitor的所有權(quán),那么當(dāng)前嘗試獲取monitor的所有權(quán)的線程會(huì)被阻塞,直
- 到monitor的進(jìn)入數(shù)變?yōu)?,才能重新嘗試獲取monitor的所有權(quán)。
- monitorexit(重要)
- 能執(zhí)行monitorexit指令的線程一定是擁有當(dāng)前對(duì)象的monitor的所有權(quán)的線程。
- 執(zhí)行monitorexit時(shí)會(huì)將monitor的進(jìn)入數(shù)減1。當(dāng)monitor的進(jìn)入數(shù)減為0時(shí),當(dāng)前線程退出
monitor,不再擁有monitor的所有權(quán),此時(shí)其他被這個(gè)monitor阻塞的線程可以嘗試去獲取這個(gè)
monitor的所有權(quán)
monitorexit釋放鎖。
monitorexit插入在方法結(jié)束處和異常處,JVM保證每個(gè)monitorenter必須有對(duì)應(yīng)的monitorexit。
tips(重要)
- 關(guān)于monitorenter和monitorexit描述
上面文字太多,杜絕去念?。。。。?!
用圖說(shuō)話?。。?! ?。。。。。。?!
類:com.syn.BTest
public static void main(String[] args) { synchronized (object) { System.out.println("Hello World -synchronized block "); } }
總結(jié):
通過(guò)上面的流程我們發(fā)現(xiàn)
1、synchronized是靠Monitor關(guān)聯(lián)拿到鎖的
2、如果競(jìng)爭(zhēng)的時(shí)候拿不到鎖,線程就去競(jìng)爭(zhēng)隊(duì)列
3、如果拿到鎖了,第二次拿,它又拿到鎖,其他線程進(jìn)入阻塞隊(duì)列
4、如果拿到鎖的線程調(diào)用了wait方法,其他線程進(jìn)入等待隊(duì)列
5、釋放鎖,需要將計(jì)數(shù)器減減操作
6、出現(xiàn)異常,也釋放鎖。
3 synchronized虛擬機(jī)源碼
synchronized是Java中的關(guān)鍵字,無(wú)法通過(guò)JDK源碼查看它的實(shí)現(xiàn),它是由JVM提供支持的,所以如果想要了解具體的實(shí)現(xiàn)需要查看JVM源碼
目標(biāo):JVM虛擬機(jī)源碼下載
http://hg.openjdk.java.net/jdk8/jdk8/hotspot/
或者
http://hg.openjdk.java.net/jdk8/jdk8/hotspot/archive/tip.zip
解壓查看即可,無(wú)需環(huán)境搭建
3.1 HotSpot源碼Monitor生成
目標(biāo): 通過(guò)JVM虛擬機(jī)源碼分析synchronized監(jiān)視器Monitor是怎么生成的
tips:
c++源碼只看重點(diǎn)、弄懂原理
c++重要嗎?不重要
但是面試時(shí)很重要,面試過(guò)去了就不重要?。。。。。。。。。。?!
學(xué)別人不會(huì)的東西你才有價(jià)值?。。?!你會(huì)、大家都會(huì),沒(méi)啥意思??!
在HotSpot虛擬機(jī)中,monitor監(jiān)視器是由ObjectMonitor實(shí)現(xiàn)的。
構(gòu)造器代碼src/share/vm/runtime/objectMonitor.hpp
hpp可以include包含cpp的東西,兩者都是c++的代碼
//構(gòu)造器 ObjectMonitor() { _header = NULL; _count = 0; _waiters = 0, _recursions = 0; // 遞歸:線程的重入次數(shù),典型的System.out.println _object = NULL; // 對(duì)應(yīng)synchronized (object)對(duì)應(yīng)里面的object _owner = NULL; // 標(biāo)識(shí)擁有該monitor的線程 _WaitSet = NULL; // 因?yàn)檎{(diào)用object.wait()方法而被阻塞的線程會(huì)被放在該隊(duì)列中 _WaitSetLock = 0 ; _Responsible = NULL; _succ = NULL; _cxq = NULL; // 競(jìng)爭(zhēng)隊(duì)列,所有請(qǐng)求鎖的線程首先會(huì)被放在這個(gè)隊(duì)列中 FreeNext = NULL; _EntryList = NULL; // 阻塞;第二輪競(jìng)爭(zhēng)鎖仍然沒(méi)有搶到的線程(偏向/可重入) _SpinFreq = 0; _SpinClock = 0; OwnerIsThread = 0; }
結(jié)論:正好印證了上面的流程圖
3.2 HotSpot源碼之Monitor競(jìng)爭(zhēng)
目標(biāo): 通過(guò)JVM虛擬機(jī)源碼分析synchronized多個(gè)線程搶奪鎖,拿到鎖之后要干什么?
monitorenter指令執(zhí)行:
JVM源碼:src/share/vm/interpreter/interpreterRuntime.cpp
JVM函數(shù): InterpreterRuntime::monitorenter函數(shù)
//鎖競(jìng)爭(zhēng)InterpreterRuntime::monitorenter IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem)) #ifdef ASSERT thread->last_frame().interpreter_frame_verify_monitor(elem); #endif if (PrintBiasedLockingStatistics) { Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); } Handle h_obj(thread, elem->obj()); assert(Universe::heap()->is_in_reserved_or_null(h_obj()), "must be NULL or an object"); //偏向鎖(非鎖:jdk14廢棄) if (UseBiasedLocking) { // Retry fast entry if bias is revoked to avoid unnecessary inflation ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK); } else { // 重量級(jí)鎖,最終調(diào)用了objectMonitor.cpp中的ObjectMonitor::enter ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK); ...略
最終調(diào)用objectMonitor.cpp文件中的 ObjectMonitor::enter
src/share/vm/runtime/objectMonitor.cpp
//重量級(jí)鎖入口 void ATTR ObjectMonitor::enter(TRAPS) { Thread * const Self = THREAD ; void * cur ; // 1、通過(guò)CAS(原子操作)操作嘗試把monitor的_owner字段設(shè)置為當(dāng)前線程(開始競(jìng)爭(zhēng)) cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ; if (cur == NULL) { // Either ASSERT _recursions == 0 or explicitly set _recursions = 0. assert (_recursions == 0 , "invariant") ; assert (_owner == Self, "invariant") ; // CONSIDER: set or assert OwnerIsThread == 1 return ; } // 2、拿到鎖;計(jì)數(shù)+1,recursions++ if (cur == Self) { _recursions ++ ;//第一次進(jìn)入(計(jì)數(shù)+1) return ; } if (Self->is_lock_owned ((address)cur)) { assert (_recursions == 0, "internal state error"); _recursions = 1 ; _owner = Self ; OwnerIsThread = 1 ; return ; } assert (Self->_Stalled == 0, "invariant") ; Self->_Stalled = intptr_t(this) ; if (Knob_SpinEarly && TrySpin (Self) > 0) { assert (_owner == Self , "invariant") ; assert (_recursions == 0 , "invariant") ; assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ; Self->_Stalled = 0 ; return ; } assert (_owner != Self , "invariant") ; assert (_succ != Self , "invariant") ; assert (Self->is_Java_thread() , "invariant") ; JavaThread * jt = (JavaThread *) Self ; assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ; assert (jt->thread_state() != _thread_blocked , "invariant") ; assert (this->object() != NULL , "invariant") ; assert (_count >= 0, "invariant") ; Atomic::inc_ptr(&_count); EventJavaMonitorEnter event; { JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this); DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt); if (JvmtiExport::should_post_monitor_contended_enter()) { JvmtiExport::post_monitor_contended_enter(jt, this); } OSThreadContendState osts(Self->osthread()); ThreadBlockInVM tbivm(jt); Self->set_current_pending_monitor(this); for (;;) { jt->set_suspend_equivalent(); // cleared by handle_special_suspend_equivalent_condition() // or java_suspend_self() // 3、獲取鎖失敗的線程,則等待?。。。。。。。。。。。。。。。。。。。。。。?! EnterI (THREAD) ; if (!ExitSuspendEquivalent(jt)) break ; _recursions = 0 ; _succ = NULL ; exit (false, Self) ; jt->java_suspend_self(); } Self->set_current_pending_monitor(NULL); }
總結(jié)
- 通過(guò)CAS嘗試把monitor的owner字段設(shè)置為當(dāng)前線程。
- 如果設(shè)置之前的owner指向當(dāng)前線程,說(shuō)明當(dāng)前線程再次進(jìn)入monitor,即重入鎖,執(zhí)行
- recursions ++ ,記錄重入的次數(shù)。
- 獲取鎖失敗的線程,則【等待】鎖的釋放。
- 一句話總結(jié):自旋拿鎖、拿到+1 、拿不到等待(競(jìng)爭(zhēng)隊(duì)列)
3.3 HotSpot源碼之Monitor等待
目標(biāo): 通過(guò)JVM虛擬機(jī)源碼分析synchronized拿不到鎖的線程他們都去干什么了?
還是 /objectMonitor.cpp
還是EnterI函數(shù)
路徑:src/share/vm/runtime/objectMonitor.cpp的
//拿不到鎖的線程他們都去干什么了?? void ATTR ObjectMonitor::EnterI (TRAPS) { Thread * Self = THREAD ; assert (Self->is_Java_thread(), "invariant") ; assert (((JavaThread *) Self)->thread_state() == _thread_blocked , "invariant") ; // 沒(méi)拿到鎖,還是要嘗試TryLock一次 if (TryLock (Self) > 0) { //拿到鎖執(zhí)行,在返回 assert (_succ != Self , "invariant") ; assert (_owner == Self , "invariant") ; assert (_Responsible != Self , "invariant") ; return ;//成功獲取 } DeferredInitialize () ; //沒(méi)拿到鎖,開始TrySpin自旋(CAS,while循環(huán)) if (TrySpin (Self) > 0) { assert (_owner == Self , "invariant") ; assert (_succ != Self , "invariant") ; assert (_Responsible != Self , "invariant") ; return ; } assert (_succ != Self , "invariant") ; assert (_owner != Self , "invariant") ; assert (_Responsible != Self , "invariant") ; // 實(shí)在拿不到鎖;當(dāng)前線程被封裝成ObjectWaiter對(duì)象node,狀態(tài)設(shè)置成ObjectWaiter::TS_CXQ //即將放入競(jìng)爭(zhēng)隊(duì)列 ObjectWaiter node(Self) ; Self->_ParkEvent->reset() ; node._prev = (ObjectWaiter *) 0xBAD ; node.TState = ObjectWaiter::TS_CXQ ; ObjectWaiter * nxt ; for (;;) { node._next = nxt = _cxq ; //使用內(nèi)核函數(shù)cmpxchg_ptr 將沒(méi)有拿到鎖線程(node)放到競(jìng)爭(zhēng)隊(duì)列 if (Atomic::cmpxchg_ptr (&node, &_cxq, nxt) == nxt) break ; if (TryLock (Self) > 0) { assert (_succ != Self , "invariant") ; assert (_owner == Self , "invariant") ; assert (_Responsible != Self , "invariant") ; return ; } } if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) { Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ; } TEVENT (Inflated enter - Contention) ; int nWakeups = 0 ; int RecheckInterval = 1 ; //將競(jìng)爭(zhēng)隊(duì)列線程掛起 for (;;) { // 線程在被掛起前做一下掙扎,看能不能獲取到鎖 if (TryLock (Self) > 0) break ; assert (_owner != Self, "invariant") ; if ((SyncFlags & 2) && _Responsible == NULL) { Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ; } // park self if (_Responsible == Self || (SyncFlags & 1)) { TEVENT (Inflated enter - park TIMED) ; Self->_ParkEvent->park ((jlong) RecheckInterval) ; // Increase the RecheckInterval, but clamp the value. RecheckInterval *= 8 ; if (RecheckInterval > 1000) RecheckInterval = 1000 ; } else { TEVENT (Inflated enter - park UNTIMED) ; // 掛起!!!!!!::通過(guò)park將當(dāng)前線程掛起(不被執(zhí)行了),等待被喚 醒?。。。。。。。。。?! Self->_ParkEvent->park() ; } //當(dāng)該線程被喚醒時(shí),執(zhí)行TryLock----->ObjectMonitor::TryLoc ?。。。。。。。。。。。。。。。。。。。?! if (TryLock(Self) > 0) break ;
當(dāng)該線程被喚醒時(shí),會(huì)從掛起的點(diǎn)繼續(xù)執(zhí)行,通過(guò) ObjectMonitor::TryLock 嘗試獲取鎖
總結(jié)
4. 競(jìng)爭(zhēng)失敗的線程被封裝成ObjectWaiter對(duì)象node,狀態(tài)設(shè)置成ObjectWaiter::TS_CXQ(競(jìng)爭(zhēng)隊(duì)
列)
5. 在for循環(huán)中,通過(guò)CAS把node節(jié)點(diǎn)push到_cxq列表中,(競(jìng)爭(zhēng)隊(duì)列)
6. node節(jié)點(diǎn)push到_cxq列表之后,通過(guò)自旋嘗試獲取鎖,如果還是沒(méi)有獲取到鎖,則通過(guò)park將當(dāng)
前線程掛起,等待被喚醒。
7. 當(dāng)該線程被喚醒時(shí),會(huì)從掛起的點(diǎn)繼續(xù)執(zhí)行,通過(guò) ObjectMonitor::TryLock 嘗試獲取鎖。
一句話總結(jié):沒(méi)拿到,嘗試拿一次、在自旋去拿、實(shí)在拿不到就去競(jìng)爭(zhēng)隊(duì)列、等待喚醒
3.4 HotSpot源碼之Monitor釋放
目標(biāo): 通過(guò)JVM虛擬機(jī)源碼分析synchronized拿到鎖的線程最后是怎么釋放鎖的?
執(zhí)行monitorexit指令
還是 /objectMonitor.cpp
里面的exit函數(shù)
Osrc/share/vm/runtime/objectMonitor.cpp
//線程釋放調(diào)用exit方法 void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) { Thread * Self = THREAD ; if (THREAD != _owner) { if (THREAD->is_lock_owned((address) _owner)) { assert (_recursions == 0, "invariant") ; _owner = THREAD ; _recursions = 0 ; OwnerIsThread = 1 ; } else { TEVENT (Exit - Throw IMSX) ; assert(false, "Non-balanced monitor enter/exit!"); if (false) { THROW(vmSymbols::java_lang_IllegalMonitorStateException()); } return; } } //_recursions計(jì)數(shù)不等于0;說(shuō)明還沒(méi)出代碼塊;進(jìn)入減減操作, if (_recursions != 0) { _recursions--; // this is simple recursive enter TEVENT (Inflated exit - recursive) ; return ; } if ((SyncFlags & 4) == 0) { _Responsible = NULL ; } #if INCLUDE_TRACE if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) { _previous_owner_tid = SharedRuntime::get_java_tid(Self); } #endif for (;;) { assert (THREAD == _owner, "invariant") ; if (Knob_ExitPolicy == 0) { OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock OrderAccess::storeload() ; // See if we need to wake a successor if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) { TEVENT (Inflated exit - simple egress) ; return ; } TEVENT (Inflated exit - complex egress) ; if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) { return ; } TEVENT (Exit - Reacquired) ; } else { if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) { OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock OrderAccess::storeload() ; // Ratify the previously observed values. if (_cxq == NULL || _succ != NULL) { TEVENT (Inflated exit - simple egress) ; return ; } if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) { TEVENT (Inflated exit - reacquired succeeded) ; return ; } TEVENT (Inflated exit - reacquired failed) ; } else { TEVENT (Inflated exit - complex egress) ; } } guarantee (_owner == THREAD, "invariant") ; // 計(jì)數(shù)為0;開始喚醒cq競(jìng)爭(zhēng)隊(duì)列、enteryList阻塞隊(duì)列 ObjectWaiter * w = NULL ;//w就是被喚醒的線程 int QMode = Knob_QMode ; // qmode = 2:直接繞過(guò)EntryList阻塞隊(duì)列,從cxq(競(jìng)爭(zhēng))隊(duì)列中獲取線程用于競(jìng)爭(zhēng)鎖 if (QMode == 2 && _cxq != NULL) { w = _cxq ; assert (w != NULL, "invariant") ; assert (w->TState == ObjectWaiter::TS_CXQ, "Invariant") ; ExitEpilog (Self, w) ; return ; } // qmode =3:cxq(競(jìng)爭(zhēng))隊(duì)列插入EntryList(阻塞)尾部; if (QMode == 3 && _cxq != NULL) { w = _cxq ; for (;;) { assert (w != NULL, "Invariant") ; ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ; if (u == w) break ; w = u ; } assert (w != NULL , "invariant") ; ObjectWaiter * q = NULL ; ObjectWaiter * p ; for (p = w ; p != NULL ; p = p->_next) { guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ; p->TState = ObjectWaiter::TS_ENTER ; p->_prev = q ; q = p ; } // Append the RATs to the EntryList // TODO: organize EntryList as a CDLL so we can locate the tail in constant-time. ObjectWaiter * Tail ; for (Tail = _EntryList ; Tail != NULL && Tail->_next != NULL ; Tail = Tail->_next) ; if (Tail == NULL) { _EntryList = w ; } else { Tail->_next = w ; w->_prev = Tail ; } } // qmode =4:cxq隊(duì)列插入到_EntryList頭部 if (QMode == 4 && _cxq != NULL) { // Aggressively drain cxq into EntryList at the first opportunity. // This policy ensure that recently-run threads live at the head of EntryList. // Drain _cxq into EntryList - bulk transfer. // First, detach _cxq. // The following loop is tantamount to: w = swap (&cxq, NULL) w = _cxq ; for (;;) { assert (w != NULL, "Invariant") ; ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ; if (u == w) break ; w = u ; } assert (w != NULL , "invariant") ; ObjectWaiter * q = NULL ; ObjectWaiter * p ; for (p = w ; p != NULL ; p = p->_next) { guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ; p->TState = ObjectWaiter::TS_ENTER ; p->_prev = q ; q = p ; } // Prepend the RATs to the EntryList if (_EntryList != NULL) { q->_next = _EntryList ; _EntryList->_prev = q ; } _EntryList = w ; // Fall thru into code that tries to wake a successor from EntryList } w = _EntryList ; if (w != NULL) { assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ; ExitEpilog (Self, w) ;//喚醒w?。。。。。。。。。。?!!!!!!!!!!! ------->當(dāng)前 類的ExitEpilog return ; }
實(shí)現(xiàn)如下
void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) { assert (_owner == Self, "invariant") ; _succ = Knob_SuccEnabled ? Wakee->_thread : NULL ; ParkEvent * Trigger = Wakee->_event ; Wakee = NULL ; // Drop the lock OrderAccess::release_store_ptr (&_owner, NULL) ; OrderAccess::fence() ; // ST _owner vs LD in unpark() if (SafepointSynchronize::do_call_back()) { TEVENT (unpark before SAFEPOINT) ; } DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self); // 喚醒之前被park()掛起的線程. Trigger->unpark() ;// invoke ObjectMonitor::EnterI 方法,繼續(xù)競(jìng)爭(zhēng) if (ObjectMonitor::_sync_Parks != NULL) { ObjectMonitor::_sync_Parks->inc() ; } }
被喚醒的線程,回到 ObjectMonitor::EnterI (TRAPS) 的第600行,繼續(xù)執(zhí)行monitor 的競(jìng)爭(zhēng)。
// park self if (_Responsible == Self || (SyncFlags & 1)) { TEVENT (Inflated enter - park TIMED) ; Self->_ParkEvent->park ((jlong) RecheckInterval) ; // Increase the RecheckInterval, but clamp the value. RecheckInterval *= 8 ; if (RecheckInterval > 1000) RecheckInterval = 1000 ; } else { TEVENT (Inflated enter - park UNTIMED) ; Self->_ParkEvent->park() ; } //喚醒之后就開始搶奪鎖 if (TryLock(Self) > 0) break ;
TryLock方 法實(shí)現(xiàn)如下:
//線程嘗試獲取鎖(or 線程被喚醒后獲?。? int ObjectMonitor::TryLock (Thread * Self) { for (;;) { void * own = _owner ; if (own != NULL) return 0 ; //獲取 if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) { // Either guarantee _recursions == 0 or set _recursions = 0. assert (_recursions == 0, "invariant") ; assert (_owner == Self, "invariant") ; // 嘗試拿到鎖返回1 return 1 ; } //拿不到鎖返回-1 if (true) return -1 ; } }
總結(jié)
1、先進(jìn)入減減操作,直到為0
2、為0后,喚醒競(jìng)爭(zhēng)隊(duì)列的線程
3、喚醒線程后,繼續(xù)爭(zhēng)奪鎖,循環(huán)前面的步驟(鎖競(jìng)爭(zhēng)-----等待----釋放)
一句話總結(jié):釋放后,進(jìn)入減減操作、直到為0然后喚醒隊(duì)列,讓他們?nèi)?zhēng)奪鎖,循環(huán)前面步驟
到此這篇關(guān)于Java同步鎖Synchronized底層源碼和原理剖析的文章就介紹到這了,更多相關(guān)Java同步鎖Synchronized內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java必會(huì)的Synchronized底層原理剖析
- Java synchronized底層的實(shí)現(xiàn)原理
- java并發(fā)編程synchronized底層實(shí)現(xiàn)原理
- Java?synchronized底層實(shí)現(xiàn)原理以及鎖優(yōu)化
- Java并發(fā)編程深入理解之Synchronized的使用及底層原理詳解 下
- Java并發(fā)編程深入理解之Synchronized的使用及底層原理詳解 上
- Java 并發(fā)編程學(xué)習(xí)筆記之Synchronized底層優(yōu)化
- Java Synchronized字節(jié)碼層分析體驗(yàn)
相關(guān)文章
Spring的@CrossOrigin注解處理請(qǐng)求源碼解析
這篇文章主要介紹了Spring的@CrossOrigin注解處理請(qǐng)求源碼解析,@CrossOrigin源碼解析主要分為兩個(gè)階段@CrossOrigin注釋的方法掃描注冊(cè),請(qǐng)求匹配@CrossOrigin注釋的方法,本文從源碼角度進(jìn)行解析,需要的朋友可以參考下2023-12-12SpringBoot結(jié)合JWT登錄權(quán)限控制的實(shí)現(xiàn)
本文主要介紹了SpringBoot結(jié)合JWT登錄權(quán)限控制的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Swagger中@API?tags中含有中文異常問(wèn)題的解決
這篇文章主要介紹了Swagger中@API?tags中含有中文異常問(wèn)題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01Java 數(shù)組轉(zhuǎn)List的四種方式小結(jié)
最近看了下數(shù)組轉(zhuǎn)List的實(shí)現(xiàn)方法,總共有4種,本文就詳細(xì)的介紹一下,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09