Java同步鎖Synchronized底層源碼和原理剖析(推薦)
1 synchronized場景回顧
目標:
synchronized回顧(鎖分類–>多線程)
概念
synchronized:是Java中的關(guān)鍵字,是一種同步鎖。
Java中鎖分為以下幾種:
樂觀鎖、悲觀鎖(syn)
獨享鎖(syn)、共享鎖
公平鎖、非公平鎖(syn)
互斥鎖(syn)、讀寫鎖
可重入鎖(syn)
分段鎖
synchronized JDK1.6鎖升級(無鎖 -> 偏向鎖 (非鎖)-> 輕量級鎖 -> 重量級鎖(1.6前都是)【面試常問】
tips:
為什么用到鎖?大家肯定會想到多線程(并發(fā))
接下來,我們一起簡單回顧下多線程特性
多線程特性回顧(面試常問)原子性:指一個操作或者多個操作,要么全部執(zhí)行并且執(zhí)行的過程不會被任何因素打斷,要么就都不執(zhí)
行可見性:是指多個線程訪問一個資源時,該資源的狀態(tài)、值信息等對于其他線程都是可見的。有序性:指程序中代碼的執(zhí)行順序 (編譯器會重排)
原子性實現(xiàn)回顧
保證了原子性?
com.syn.com.syn.th.SyncAtomicity
package com.syn.com.syn.th;
import java.util.concurrent.TimeUnit;
/*
目標:測試原子性問題
1、調(diào)用正常(不加鎖)方法;兩個線程都可以正常執(zhí)行
2、調(diào)用加鎖方法,只能有一個線程正常執(zhí)行,其他線程排隊等候
*/
public class SyncAtomicity {
public static void main(String[] args) throws InterruptedException {
SyncAtomicity syncAtomicity = new SyncAtomicity();
//synchronized修飾實例方法
//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("進入testSYNC方法>>>>>>>>>>>>>>>>>>>>>");
try {
//模擬方法體尚未執(zhí)行完畢
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//加鎖方法
public synchronized static void testSYNCForStatic() {
System.out.println("進入testSYNC方法>>>>>>>>>>>>>>>>>>>>>");
try {
//模擬方法體尚未執(zhí)行完畢
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//正常方法
public void test() {
System.out.println("進入test方法>>>>>>>>>>>>>>>>>>>>>");
try {
//模擬方法體尚未執(zhí)行完畢
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
總結(jié)
我們發(fā)現(xiàn)在同一時刻確實只有一個線程進入,保證了原子性
這是什么原理呢?
2 反匯編尋找鎖實現(xiàn)原理
目標 通過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自帶的一個工具: javap ,對字節(jié)碼進行反匯編:
//com.syn.BTest javap -v -c BTest.class
反匯編后

解釋
被synchronized修飾的代碼塊,多了兩個指令
monitorenter、monitorexit
即JVM使用monitorenter和monitorexit兩個指令實現(xiàn)同步

解釋
被synchronized修飾的方法;增加 了ACC_SYNCHRONIZED 修飾。會隱式調(diào)用monitorenter和
monitorexit。
monitorenter原理(重要)
monitorenter首先我們來看一下JVM規(guī)范中對于monitorenter的描述
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.monitorenter

翻譯如下:
每一個對象都會和一個監(jiān)視器monitor關(guān)聯(lián)。
監(jiān)視器被占用時會被鎖住,其他線程無法來獲取該monitor。
當JVM執(zhí)行某個線程的某個方法內(nèi)部的monitorenter時,它會嘗試去獲取當前對象對應(yīng)的monitor的所有權(quán)。其過程如下:
- 若monior的進入數(shù)為0,線程可以進入monitor,并將monitor的進入數(shù)置為1。當前線程成為
- monitor的owner(所有者)
- 若線程已擁有monitor的所有權(quán),允許它重入monitor,則進入monitor的進入數(shù)加1
- 若其他線程已經(jīng)占有monitor的所有權(quán),那么當前嘗試獲取monitor的所有權(quán)的線程會被阻塞,直
- 到monitor的進入數(shù)變?yōu)?,才能重新嘗試獲取monitor的所有權(quán)。
- monitorexit(重要)
- 能執(zhí)行monitorexit指令的線程一定是擁有當前對象的monitor的所有權(quán)的線程。
- 執(zhí)行monitorexit時會將monitor的進入數(shù)減1。當monitor的進入數(shù)減為0時,當前線程退出
monitor,不再擁有monitor的所有權(quán),此時其他被這個monitor阻塞的線程可以嘗試去獲取這個
monitor的所有權(quán)
monitorexit釋放鎖。
monitorexit插入在方法結(jié)束處和異常處,JVM保證每個monitorenter必須有對應(yīng)的monitorexit。
tips(重要)
- 關(guān)于monitorenter和monitorexit描述
上面文字太多,杜絕去念?。。。。。?br />用圖說話?。。?! ?。。。。。。?!

類:com.syn.BTest
public static void main(String[] args) {
synchronized (object) {
System.out.println("Hello World -synchronized block ");
}
}總結(jié):
通過上面的流程我們發(fā)現(xiàn)
1、synchronized是靠Monitor關(guān)聯(lián)拿到鎖的
2、如果競爭的時候拿不到鎖,線程就去競爭隊列
3、如果拿到鎖了,第二次拿,它又拿到鎖,其他線程進入阻塞隊列
4、如果拿到鎖的線程調(diào)用了wait方法,其他線程進入等待隊列
5、釋放鎖,需要將計數(shù)器減減操作
6、出現(xiàn)異常,也釋放鎖。
3 synchronized虛擬機源碼
synchronized是Java中的關(guān)鍵字,無法通過JDK源碼查看它的實現(xiàn),它是由JVM提供支持的,所以如果想要了解具體的實現(xiàn)需要查看JVM源碼
目標:JVM虛擬機源碼下載
http://hg.openjdk.java.net/jdk8/jdk8/hotspot/
或者
http://hg.openjdk.java.net/jdk8/jdk8/hotspot/archive/tip.zip

解壓查看即可,無需環(huán)境搭建
3.1 HotSpot源碼Monitor生成
目標: 通過JVM虛擬機源碼分析synchronized監(jiān)視器Monitor是怎么生成的
tips:
c++源碼只看重點、弄懂原理
c++重要嗎?不重要
但是面試時很重要,面試過去了就不重要?。。。。。。。。。。?!
學(xué)別人不會的東西你才有價值?。。?!你會、大家都會,沒啥意思??!
在HotSpot虛擬機中,monitor監(jiān)視器是由ObjectMonitor實現(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; // 對應(yīng)synchronized (object)對應(yīng)里面的object
_owner = NULL; // 標識擁有該monitor的線程
_WaitSet = NULL; // 因為調(diào)用object.wait()方法而被阻塞的線程會被放在該隊列中
_WaitSetLock = 0 ;
_Responsible = NULL;
_succ = NULL;
_cxq = NULL; // 競爭隊列,所有請求鎖的線程首先會被放在這個隊列中
FreeNext = NULL;
_EntryList = NULL; // 阻塞;第二輪競爭鎖仍然沒有搶到的線程(偏向/可重入)
_SpinFreq = 0;
_SpinClock = 0;
OwnerIsThread = 0;
}
結(jié)論:正好印證了上面的流程圖
3.2 HotSpot源碼之Monitor競爭
目標: 通過JVM虛擬機源碼分析synchronized多個線程搶奪鎖,拿到鎖之后要干什么?

monitorenter指令執(zhí)行:
JVM源碼:src/share/vm/interpreter/interpreterRuntime.cpp
JVM函數(shù): InterpreterRuntime::monitorenter函數(shù)
//鎖競爭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 {
// 重量級鎖,最終調(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
//重量級鎖入口
void ATTR ObjectMonitor::enter(TRAPS) {
Thread * const Self = THREAD ;
void * cur ;
// 1、通過CAS(原子操作)操作嘗試把monitor的_owner字段設(shè)置為當前線程(開始競爭)
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、拿到鎖;計數(shù)+1,recursions++
if (cur == Self) {
_recursions ++ ;//第一次進入(計數(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é)
- 通過CAS嘗試把monitor的owner字段設(shè)置為當前線程。
- 如果設(shè)置之前的owner指向當前線程,說明當前線程再次進入monitor,即重入鎖,執(zhí)行
- recursions ++ ,記錄重入的次數(shù)。
- 獲取鎖失敗的線程,則【等待】鎖的釋放。
- 一句話總結(jié):自旋拿鎖、拿到+1 、拿不到等待(競爭隊列)
3.3 HotSpot源碼之Monitor等待
目標: 通過JVM虛擬機源碼分析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") ;
// 沒拿到鎖,還是要嘗試TryLock一次
if (TryLock (Self) > 0) {
//拿到鎖執(zhí)行,在返回
assert (_succ != Self , "invariant") ;
assert (_owner == Self , "invariant") ;
assert (_Responsible != Self , "invariant") ;
return ;//成功獲取
}
DeferredInitialize () ;
//沒拿到鎖,開始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") ;
// 實在拿不到鎖;當前線程被封裝成ObjectWaiter對象node,狀態(tài)設(shè)置成ObjectWaiter::TS_CXQ
//即將放入競爭隊列
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 將沒有拿到鎖線程(node)放到競爭隊列
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 ;
//將競爭隊列線程掛起
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) ;
// 掛起!!!!!!::通過park將當前線程掛起(不被執(zhí)行了),等待被喚
醒?。。。。。。。。。。?
Self->_ParkEvent->park() ;
}
//當該線程被喚醒時,執(zhí)行TryLock----->ObjectMonitor::TryLoc
!?。。。。。。。。。。。。。。。。。。?!
if (TryLock(Self) > 0) break ;
當該線程被喚醒時,會從掛起的點繼續(xù)執(zhí)行,通過 ObjectMonitor::TryLock 嘗試獲取鎖
總結(jié)
4. 競爭失敗的線程被封裝成ObjectWaiter對象node,狀態(tài)設(shè)置成ObjectWaiter::TS_CXQ(競爭隊
列)
5. 在for循環(huán)中,通過CAS把node節(jié)點push到_cxq列表中,(競爭隊列)
6. node節(jié)點push到_cxq列表之后,通過自旋嘗試獲取鎖,如果還是沒有獲取到鎖,則通過park將當
前線程掛起,等待被喚醒。
7. 當該線程被喚醒時,會從掛起的點繼續(xù)執(zhí)行,通過 ObjectMonitor::TryLock 嘗試獲取鎖。
一句話總結(jié):沒拿到,嘗試拿一次、在自旋去拿、實在拿不到就去競爭隊列、等待喚醒
3.4 HotSpot源碼之Monitor釋放
目標: 通過JVM虛擬機源碼分析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計數(shù)不等于0;說明還沒出代碼塊;進入減減操作,
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") ;
// 計數(shù)為0;開始喚醒cq競爭隊列、enteryList阻塞隊列
ObjectWaiter * w = NULL ;//w就是被喚醒的線程
int QMode = Knob_QMode ;
// qmode = 2:直接繞過EntryList阻塞隊列,從cxq(競爭)隊列中獲取線程用于競爭鎖
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(競爭)隊列插入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隊列插入到_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!?。。。。。。。。。?!!!!!!!!!!! ------->當前
類的ExitEpilog
return ;
}
實現(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ù)競爭
if (ObjectMonitor::_sync_Parks != NULL) {
ObjectMonitor::_sync_Parks->inc() ;
}
}
被喚醒的線程,回到 ObjectMonitor::EnterI (TRAPS) 的第600行,繼續(xù)執(zhí)行monitor 的競爭。
// 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方 法實現(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、先進入減減操作,直到為0
2、為0后,喚醒競爭隊列的線程
3、喚醒線程后,繼續(xù)爭奪鎖,循環(huán)前面的步驟(鎖競爭-----等待----釋放)
一句話總結(jié):釋放后,進入減減操作、直到為0然后喚醒隊列,讓他們?nèi)帄Z鎖,循環(huán)前面步驟
到此這篇關(guān)于Java同步鎖Synchronized底層源碼和原理剖析的文章就介紹到這了,更多相關(guān)Java同步鎖Synchronized內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot結(jié)合JWT登錄權(quán)限控制的實現(xiàn)
本文主要介紹了SpringBoot結(jié)合JWT登錄權(quán)限控制的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2022-07-07
Java 數(shù)組轉(zhuǎn)List的四種方式小結(jié)
最近看了下數(shù)組轉(zhuǎn)List的實現(xiàn)方法,總共有4種,本文就詳細的介紹一下,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09

