目錄
1、AddWaiter / DequeueWaiter /DequeueSpecificWaiter
2、wait
3、notify
4、notifyAll
5、exit
6、try_enter / complete_exit
7、總結
本篇部落格繼續上一篇《Hotspot 重量級鎖ObjectMonitor(一) 源碼解析》将ObjectMonitor的其他關鍵方法的實作。
1、AddWaiter / DequeueWaiter /DequeueSpecificWaiter
AddWaiter方法用于将目标ObjectWaiter加入到雙向循環連結清單中,DequeueWaiter用于移除連結清單頭_WaitSet對應的節點,該節點是最早加入到連結清單的,即按照加傳入連結表的先後順序依次從連結清單中移除,DequeueSpecificWaiter用于移除指定節點,不一定是_WaitSet對應的節點。其實作如下:
inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
assert(node != NULL, "should not dequeue NULL node");
assert(node->_prev == NULL, "node already in list");
assert(node->_next == NULL, "node already in list");
//将目标節點放入一個雙向的循環連結清單中
if (_WaitSet == NULL) {
//如果_WaitSet還是空的,目前節點就是第一個
_WaitSet = node;
node->_prev = node;
node->_next = node;
} else {
//如果_WaitSet不是空的,将其插入到head的prev節點上
ObjectWaiter* head = _WaitSet ;
ObjectWaiter* tail = head->_prev;
assert(tail->_next == head, "invariant check");
//注意tail在初始狀态下就是head,是以插入第二個節點時修改next屬性,實際是修改head的next屬性
tail->_next = node;
head->_prev = node;
node->_next = head;
node->_prev = tail;
}
}
inline ObjectWaiter* ObjectMonitor::DequeueWaiter() {
// dequeue the very first waiter
ObjectWaiter* waiter = _WaitSet;
if (waiter) {
//如果_WaitSet為不空
DequeueSpecificWaiter(waiter);
}
return waiter;
}
inline void ObjectMonitor::DequeueSpecificWaiter(ObjectWaiter* node) {
assert(node != NULL, "should not dequeue NULL node");
assert(node->_prev != NULL, "node already removed from list");
assert(node->_next != NULL, "node already removed from list");
//從_WaitSet中取出一個ObjectWaiter,實際就是取出_WaitSet對應的head節點,該
//節點是最早加入到連結清單中的
ObjectWaiter* next = node->_next;
if (next == node) {
//_WaitSet隻有一個節點
assert(node->_prev == node, "invariant check");
_WaitSet = NULL;
} else {
//将node從連結清單中移除
ObjectWaiter* prev = node->_prev;
assert(prev->_next == node, "invariant check");
assert(next->_prev == node, "invariant check");
next->_prev = prev;
prev->_next = next;
if (_WaitSet == node) {
//如果移除的就是_WaitSet,将next置為_WaitSet
_WaitSet = next;
}
}
//相關屬性置為null
node->_next = NULL;
node->_prev = NULL;
}
上述邏輯可以結合以下用例來了解,如下:
//依次添加node,node2,node3,node4,node5 5個節點時各節點的引用關系
prev next
----------------
node node node
=================
node2 node node2
node node2 node
=================
node node2 node3
node3 node node2
node2 node3 node
=================
node2 node3 node4
node4 node node2
node3 node4 node
node node2 node3 //node2節點的引用關系不變
=================
node3 node4 node5
node5 node node2
node4 node5 node
node node2 node3 //node2和node3節點的引用關系不變
node2 node3 node4
删除node節點後node2作為_WaitSet
================
node4 node5 node2
node5 node2 node3
node node2 node3 //node2和node3節點的引用關系不變
node2 node3 node4
2、wait
wait方法是Object的wait方法的底層實作,該方法會建立一個ObjectWaiter并加入到連結清單中,然後釋放占有的鎖,讓目前線程休眠,當目前線程因為等待逾時,被中斷或者被其他線程喚醒時就再次搶占鎖,搶占邏輯就是之前的enter方法,搶占成功後wait方法退出。
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
//擷取目前線程
Thread * const Self = THREAD ;
assert(Self->is_Java_thread(), "Must be Java thread!");
JavaThread *jt = (JavaThread *)THREAD;
//初始化配置,如果已經初始化則傳回
DeferredInitialize () ;
//檢查目前線程是否擷取了鎖,如果沒有則抛出異常
CHECK_OWNER();
EventJavaMonitorWait event;
//如果線程被中斷了且不是因為未處理異常導緻的
if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
//釋出JVMTI事件
if (JvmtiExport::should_post_monitor_waited()) {
JvmtiExport::post_monitor_waited(jt, this, false);
}
if (event.should_commit()) {
post_monitor_wait_event(&event, 0, millis, false);
}
TEVENT (Wait - Throw IEX) ;
//抛出異常
THROW(vmSymbols::java_lang_InterruptedException());
return ;
}
TEVENT (Wait) ;
assert (Self->_Stalled == 0, "invariant") ;
//設定屬性,記錄目前線程等待的ObjectMonitor
Self->_Stalled = intptr_t(this) ;
jt->set_current_waiting_monitor(this);
//建立ObjectWaiter,将其狀态置為TS_WAIT
ObjectWaiter node(Self);
node.TState = ObjectWaiter::TS_WAIT ;
Self->_ParkEvent->reset() ;
OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag
//擷取操作ObjectWaiter連結清單的鎖_WaitSetLock
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ;
//将目前節點插入到ObjectWaiter連結清單中
AddWaiter (&node) ;
//釋放鎖
Thread::SpinRelease (&_WaitSetLock) ;
//SyncFlags預設為0
if ((SyncFlags & 4) == 0) {
_Responsible = NULL ;
}
intptr_t save = _recursions; // record the old recursion count
//等待的線程數加1
_waiters++; // increment the number of waiters
_recursions = 0; // set the recursion level to be 1
//釋放該鎖
exit (true, Self) ; // exit the monitor
guarantee (_owner != Self, "invariant") ;
// TODO-FIXME: change the following logic to a loop of the form
// while (!timeout && !interrupted && _notified == 0) park()
int ret = OS_OK ;
int WasNotified = 0 ;
{ // State transition wrappers
OSThread* osthread = Self->osthread();
//修改線程狀态為OBJECT_WAIT
OSThreadWaitState osts(osthread, true);
{
//修改線程狀态從_thread_in_vm到_thread_blocked
ThreadBlockInVM tbivm(jt);
// Thread is in thread_blocked state and oop access is unsafe.
jt->set_suspend_equivalent();
if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) {
// Intentionally empty
} else
if (node._notified == 0) { //_notified為0表示沒有其他線程喚醒
//将目前線程park,讓其處于休眠狀态
if (millis <= 0) {
Self->_ParkEvent->park () ;
} else {
ret = Self->_ParkEvent->park (millis) ;
}
}
//目前線程從park狀态被喚醒了
//ExitSuspendEquivalent預設傳回false
if (ExitSuspendEquivalent (jt)) {
// TODO-FIXME: add -- if succ == Self then succ = null.
jt->java_suspend_self();
}
} //退出代碼塊時會切換線程狀态 _thread_blocked -> _thread_in_vm
//如果是線程被中斷或者等待逾時則狀态是TS_WAIT,如果是被nofity喚醒的則應該是TS_RUN
if (node.TState == ObjectWaiter::TS_WAIT) {
//擷取鎖
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - unlink") ;
if (node.TState == ObjectWaiter::TS_WAIT) {
//如果是TS_WAIT,則将其從連結清單中移除
DequeueSpecificWaiter (&node) ; // unlink from WaitSet
assert(node._notified == 0, "invariant");
//将狀态置為TS_RUN
node.TState = ObjectWaiter::TS_RUN ;
}
//釋放鎖
Thread::SpinRelease (&_WaitSetLock) ;
}
guarantee (node.TState != ObjectWaiter::TS_WAIT, "invariant") ;
//讓修改立即生效
OrderAccess::loadload() ;
if (_succ == Self) _succ = NULL ;
WasNotified = node._notified ;
// post monitor waited event. Note that this is past-tense, we are done waiting.
if (JvmtiExport::should_post_monitor_waited()) {
JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT);
if (node._notified != 0 && _succ == Self) {
node._event->unpark();
}
}
if (event.should_commit()) {
post_monitor_wait_event(&event, node._notifier_tid, millis, ret == OS_TIMEOUT);
}
OrderAccess::fence() ;
assert (Self->_Stalled != 0, "invariant") ;
Self->_Stalled = 0 ;
assert (_owner != Self, "invariant") ;
ObjectWaiter::TStates v = node.TState ;
if (v == ObjectWaiter::TS_RUN) {
//重新擷取該鎖
enter (Self) ;
} else {
//該ObjectWaiter已經被喚醒了,但是等待擷取鎖的時候線程被中斷了
guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
ReenterI (Self, &node) ;
node.wait_reenter_end(this);
}
guarantee (node.TState == ObjectWaiter::TS_RUN, "invariant") ;
assert (_owner == Self, "invariant") ;
assert (_succ != Self , "invariant") ;
} // OSThreadWaitState()
jt->set_current_waiting_monitor(NULL);
guarantee (_recursions == 0, "invariant") ;
_recursions = save; // restore the old recursion count
_waiters--; // decrement the number of waiters
// Verify a few postconditions
assert (_owner == Self , "invariant") ;
assert (_succ != Self , "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
if (SyncFlags & 32) {
OrderAccess::fence() ;
}
//如果不是因為notify被喚醒
if (!WasNotified) {
// 可能因為等待逾時或者Thread.interrupt()被喚醒
if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
TEVENT (Wait - throw IEX from epilog) ;
//如果線程中斷則抛出異常
THROW(vmSymbols::java_lang_InterruptedException());
}
}
}
#define CHECK_OWNER() \
do { \
if (THREAD != _owner) { \
//如果owner屬性不是目前線程
if (THREAD->is_lock_owned((address) _owner)) { \
//如果owner屬性位于目前線程棧幀中,說明該鎖是由輕量級鎖膨脹來的
//修改owner屬性為目前線程
_owner = THREAD ; /* Convert from basiclock addr to Thread addr */ \
_recursions = 0; \
OwnerIsThread = 1 ; \
} else { \
//目前線程沒有擷取鎖,則抛出異常
TEVENT (Throw IMSX) ; \
THROW(vmSymbols::java_lang_IllegalMonitorStateException()); \
} \
} \
} while (false)
bool Thread::is_interrupted(Thread* thread, bool clear_interrupted) {
trace("is_interrupted", thread);
debug_only(check_for_dangling_thread_pointer(thread);)
// 判斷其是否被中斷,如果是且clear_interrupted為true,則将其中斷辨別清除掉
return os::is_interrupted(thread, clear_interrupted);
}
bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
"possibility of dangling Thread pointer");
//擷取關聯的原生線程
OSThread* osthread = thread->osthread();
//擷取其是否被中斷
bool interrupted = osthread->interrupted();
if (interrupted && clear_interrupted) {
//清除被中斷辨別
osthread->set_interrupted(false);
}
return interrupted;
}
//ReenterI和EnterI的邏輯基本相同,用于擷取對象鎖
void ATTR ObjectMonitor::ReenterI (Thread * Self, ObjectWaiter * SelfNode) {
assert (Self != NULL , "invariant") ;
assert (SelfNode != NULL , "invariant") ;
assert (SelfNode->_thread == Self , "invariant") ;
assert (_waiters > 0 , "invariant") ;
//校驗目标對象的對象頭就是目前ObjectMonitor的指針
assert (((oop)(object()))->mark() == markOopDesc::encode(this) , "invariant") ;
assert (((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
JavaThread * jt = (JavaThread *) Self ;
int nWakeups = 0 ;
for (;;) {
ObjectWaiter::TStates v = SelfNode->TState ;
//校驗狀态
guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
assert (_owner != Self, "invariant") ;
//嘗試擷取鎖
if (TryLock (Self) > 0) break ;
//嘗試自旋擷取鎖
if (TrySpin (Self) > 0) break ;
TEVENT (Wait Reentry - parking) ;
{
//修改線程狀态
OSThreadContendState osts(Self->osthread());
ThreadBlockInVM tbivm(jt);
jt->set_suspend_equivalent();
//SyncFlags預設是0
if (SyncFlags & 1) {
Self->_ParkEvent->park ((jlong)1000) ;
} else {
Self->_ParkEvent->park () ;
}
// were we externally suspended while we were waiting?
for (;;) {
//ExitSuspendEquivalent預設傳回false
if (!ExitSuspendEquivalent (jt)) break ;
if (_succ == Self) { _succ = NULL; OrderAccess::fence(); }
jt->java_suspend_self();
jt->set_suspend_equivalent();
}
}
//嘗試擷取鎖
if (TryLock(Self) > 0) break ;
TEVENT (Wait Reentry - futile wakeup) ;
++ nWakeups ;
// Assuming this is not a spurious wakeup we'll normally
// find that _succ == Self.
if (_succ == Self) _succ = NULL ;
// Invariant: after clearing _succ a contending thread
// *must* retry _owner before parking.
OrderAccess::fence() ;
if (ObjectMonitor::_sync_FutileWakeups != NULL) {
ObjectMonitor::_sync_FutileWakeups->inc() ;
}
}//for循環結束
//for循環結束,已經擷取了鎖
assert (_owner == Self, "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
//從連結清單中移除
UnlinkAfterAcquire (Self, SelfNode) ;
if (_succ == Self) _succ = NULL ;
assert (_succ != Self, "invariant") ;
//修改狀态為TS_RUN
SelfNode->TState = ObjectWaiter::TS_RUN ;
OrderAccess::fence() ; // see comments at the end of EnterI()
}
3、notify
notify方法時Object的notify方法的底層實作,用于“喚醒”WaitSet連結清單頭對應的線程,即最早加入到該連結清單的等待線程,注意在預設配置下(預設的處理政策是2,不同政策的處理邏輯不同),并不會直接unpark該線程,而是将其加入到cxq連結清單的前面,相當于調用了一次EnterI方法。加入到cxq連結清單後,當關聯的鎖被釋放了就會unpark該線程,注意隻是喚醒,然後該線程調用enter方法搶占鎖,是以此時可能有其他線程在同時調用enter方法搶占鎖。
void ObjectMonitor::notify(TRAPS) {
//檢查目前線程是否占用該鎖,如果沒有抛出異常
CHECK_OWNER();
if (_WaitSet == NULL) {
//如果沒有等待的線程則退出
TEVENT (Empty-Notify) ;
return ;
}
//Knob_MoveNotifyee屬性預設是2
int Policy = Knob_MoveNotifyee ;
//擷取鎖
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
//将連結清單頭元素移除并傳回
ObjectWaiter * iterator = DequeueWaiter() ;
if (iterator != NULL) {
TEVENT (Notify1 - Transfer) ;
guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
guarantee (iterator->_notified == 0, "invariant") ;
if (Policy != 4) {
//将狀态置為TS_ENTER
iterator->TState = ObjectWaiter::TS_ENTER ;
}
//_notified置為1表示該ObjectWaiter被喚醒了
iterator->_notified = 1 ;
Thread * Self = THREAD;
//記錄目前線程ID
iterator->_notifier_tid = Self->osthread()->thread_id();
ObjectWaiter * List = _EntryList ;
if (List != NULL) {
assert (List->_prev == NULL, "invariant") ;
assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
assert (List != iterator, "invariant") ;
}
//根據不同的政策執行不同的處理
if (Policy == 0) { //将iterator插入到_EntryList頭元素的前面
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
List->_prev = iterator ;
iterator->_next = List ;
iterator->_prev = NULL ;
_EntryList = iterator ;
}
} else
if (Policy == 1) { //将iterator插入到_EntryList連結清單的末尾
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
ObjectWaiter * Tail ;
//不斷周遊找到連結清單最後一個元素
for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
Tail->_next = iterator ;
iterator->_prev = Tail ;
iterator->_next = NULL ;
}
} else
if (Policy == 2) { //将iterator插入到_cxq頭元素的前面
// prepend to cxq
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Front = _cxq ;
iterator->_next = Front ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
break ;
}
}
}
} else
if (Policy == 3) { //将iterator插入到_cxq連結清單末尾的後面
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Tail ;
Tail = _cxq ;
if (Tail == NULL) {
iterator->_next = NULL ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
break ;
}
} else {
//往後周遊找到最後一個元素
while (Tail->_next != NULL) Tail = Tail->_next ;
Tail->_next = iterator ;
iterator->_prev = Tail ;
iterator->_next = NULL ;
break ;
}
}
} else {
//将等待的線程直接unpark喚醒
ParkEvent * ev = iterator->_event ;
iterator->TState = ObjectWaiter::TS_RUN ;
OrderAccess::fence() ;
ev->unpark() ;
}
if (Policy < 4) {
//修改線程狀态,記錄鎖競争開始
iterator->wait_reenter_begin(this);
}
} //if結束
//釋放鎖
Thread::SpinRelease (&_WaitSetLock) ;
if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) {
//增加計數
ObjectMonitor::_sync_Notifications->inc() ;
}
}
4、notifyAll
notifyAll方法就是Object的notifyAll方法的底層實作,對單個ObjectWaiter其處理邏輯跟notify是一緻的,相比notify的實作就是增加了一個for循環,會不斷的從_WaitSet連結清單中移除頭元素,然後執行notify的處理邏輯,直到_WaitSet連結清單為空退出循環。
void ObjectMonitor::notifyAll(TRAPS) {
//檢查目前線程是否占用該鎖,如果沒有抛出異常
CHECK_OWNER();
ObjectWaiter* iterator;
if (_WaitSet == NULL) {
//如果沒有等待的線程則退出
TEVENT (Empty-NotifyAll) ;
return ;
}
//Knob_MoveNotifyee屬性預設是2
int Policy = Knob_MoveNotifyee ;
int Tally = 0 ;
//擷取鎖
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notifyall") ;
//if變成for循環
for (;;) {
//擷取頭部元素,頭部節點為最早加入到連結清單中的節點
iterator = DequeueWaiter () ;
//如果為空則終止循環
if (iterator == NULL) break ;
TEVENT (NotifyAll - Transfer1) ;
//增加計數
++Tally ;
guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
guarantee (iterator->_notified == 0, "invariant") ;
//_notified置為1表示該ObjectWaiter被喚醒了
iterator->_notified = 1 ;
Thread * Self = THREAD;
//記錄目前線程ID
iterator->_notifier_tid = Self->osthread()->thread_id();
if (Policy != 4) {
//将狀态置為TS_ENTER
iterator->TState = ObjectWaiter::TS_ENTER ;
}
//根據不同的政策執行不同的處理
ObjectWaiter * List = _EntryList ;
if (List != NULL) {
assert (List->_prev == NULL, "invariant") ;
assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
assert (List != iterator, "invariant") ;
}
if (Policy == 0) { //将iterator插入到_EntryList頭元素的前面
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
List->_prev = iterator ;
iterator->_next = List ;
iterator->_prev = NULL ;
_EntryList = iterator ;
}
} else
if (Policy == 1) { //将iterator插入到_EntryList連結清單的末尾
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
ObjectWaiter * Tail ;
for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
Tail->_next = iterator ;
iterator->_prev = Tail ;
iterator->_next = NULL ;
}
} else
if (Policy == 2) { //将iterator插入到_cxq頭元素的前面
// prepend to cxq
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Front = _cxq ;
iterator->_next = Front ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
break ;
}
}
} else
if (Policy == 3) { //将iterator插入到_cxq連結清單末尾的後面
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Tail ;
Tail = _cxq ;
if (Tail == NULL) {
iterator->_next = NULL ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
break ;
}
} else {
while (Tail->_next != NULL) Tail = Tail->_next ;
Tail->_next = iterator ;
iterator->_prev = Tail ;
iterator->_next = NULL ;
break ;
}
}
} else {
//将等待的線程直接unpark喚醒
ParkEvent * ev = iterator->_event ;
iterator->TState = ObjectWaiter::TS_RUN ;
OrderAccess::fence() ;
ev->unpark() ;
}
if (Policy < 4) {
//修改線程狀态,記錄鎖競争開始
iterator->wait_reenter_begin(this);
}
}//for循環結束
//釋放鎖
Thread::SpinRelease (&_WaitSetLock) ;
if (Tally != 0 && ObjectMonitor::_sync_Notifications != NULL) {
//增加計數
ObjectMonitor::_sync_Notifications->inc(Tally) ;
}
}
5、exit
exit用于釋放鎖,即将owner屬性置為NULL,預設配置下會通過unpark喚醒_EntryList連結清單頭部節點對應的等待線程,如果EntryList連結清單為空,則将cxq連結清單中的元素加入到EntryList連結清單中且順序保持不變,即優先喚醒最近等待的線程。注意exit方法并不會因為安全點同步而阻塞,exit方法退出後繼續執行,無論解釋執行或者編譯執行則會都被阻塞;exit方式釋放鎖後,被喚醒的線程占用了該鎖,在enter方法擷取鎖準備切換線程狀态時會被阻塞。
//第一個參數not_suspended用于debug的,可以忽略
void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) {
Thread * Self = THREAD ;
if (THREAD != _owner) {
if (THREAD->is_lock_owned((address) _owner)) {
//如果owner位于目前線程調用棧幀,說明該鎖是輕量級鎖膨脹來的
assert (_recursions == 0, "invariant") ;
//修改owner屬性
_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;
}
}
if (_recursions != 0) {
//不等于0說明是嵌套加鎖,将_recursions減1即可傳回
_recursions--; // this is simple recursive enter
TEVENT (Inflated exit - recursive) ;
return ;
}
// SyncFlags預設值是0
if ((SyncFlags & 4) == 0) {
_Responsible = NULL ;
}
for (;;) {
assert (THREAD == _owner, "invariant") ;
//Knob_ExitPolicy預設值是0
if (Knob_ExitPolicy == 0) {
//将_owner屬性置為NULL,釋放鎖,如果某個線程正在自旋搶占該鎖,則會搶占成功
//即這種政策會優先保證通過自旋搶占鎖的線程擷取鎖,而其他處于等待隊列中的線程則靠後
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) {
//如果_EntryList或者cxq連結清單都是空的,則直接傳回
TEVENT (Inflated exit - simple egress) ;
return ;
}
TEVENT (Inflated exit - complex egress) ;
//如果_EntryList或者cxq連結清單不是空的,則原子的設定owner屬性為目前線程,嘗試搶占鎖
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 ;
}
//有可能cxq插入了一個新節點,導緻上面的if不成立,需要重新擷取鎖
if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
TEVENT (Inflated exit - reacquired succeeded) ;
return ;
}
TEVENT (Inflated exit - reacquired failed) ;
} else {
//如果_EntryList或者cxq連結清單不是空的則不釋放鎖,避免二次搶占鎖,即優先處理等待隊列中的線程
TEVENT (Inflated exit - complex egress) ;
}
}
guarantee (_owner == THREAD, "invariant") ;
ObjectWaiter * w = NULL ;
//Knob_QMode的預設值是0
int QMode = Knob_QMode ;
if (QMode == 2 && _cxq != NULL) {
w = _cxq ;
assert (w != NULL, "invariant") ;
assert (w->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
//通過unpark喚醒cxq對應的線程,喚醒後會将cxq從連結清單中移除
ExitEpilog (Self, w) ;
return ;
}
if (QMode == 3 && _cxq != NULL) {
//将cxq連結清單中的元素插入到_EntryList連結清單的末尾
w = _cxq ;
for (;;) {
assert (w != NULL, "Invariant") ;
//将_cxq原子的置為NULL,如果失敗則更新w,重新嘗試直到成功為止
//置為NULL後,如果有新的節點插入進來就形成了一個新的cxq連結清單
ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
if (u == w) break ;
w = u ;
}
assert (w != NULL , "invariant") ;
ObjectWaiter * q = NULL ;
ObjectWaiter * p ;
//周遊cxq中的所有節點,将其置為TS_ENTER
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 ;
}
ObjectWaiter * Tail ;
//周遊_EntryList找到末尾元素,将w插入到後面
for (Tail = _EntryList ; Tail != NULL && Tail->_next != NULL ; Tail = Tail->_next) ;
if (Tail == NULL) {
_EntryList = w ;
} else {
Tail->_next = w ;
w->_prev = Tail ;
}
}
if (QMode == 4 && _cxq != NULL) {
//将cxq連結清單中的元素插入到_EntryList連結清單的頭部
w = _cxq ;
for (;;) {
assert (w != NULL, "Invariant") ;
//将_cxq原子的置為NULL,如果失敗則更新w,重新嘗試直到成功為止
ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
if (u == w) break ;
w = u ;
}
assert (w != NULL , "invariant") ;
ObjectWaiter * q = NULL ;
ObjectWaiter * p ;
//周遊cxq中的所有節點,将其置為TS_ENTER
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 ;
}
//插入到_EntryList的頭部
if (_EntryList != NULL) {
q->_next = _EntryList ;
_EntryList->_prev = q ;
}
_EntryList = w ;
}
w = _EntryList ;
if (w != NULL) {
//通過unpark喚醒w對應的線程,喚醒後會該線程會負責将w從EntryList連結清單中移除
assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
ExitEpilog (Self, w) ;
return ;
}
//如果_EntryList為空
w = _cxq ;
if (w == NULL) continue ;//如果cxq為空則重新循環,不會進入此分支
//cxq不為NULL
for (;;) {
assert (w != NULL, "Invariant") ;
//将cxq原子的修改為NULL
ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
if (u == w) break ;
w = u ;
}
TEVENT (Inflated exit - drain cxq into EntryList) ;
assert (w != NULL , "invariant") ;
assert (_EntryList == NULL , "invariant") ;
if (QMode == 1) {
//周遊cxq中的元素将其加入到_EntryList中,注意順序跟cxq中是返的
ObjectWaiter * s = NULL ;
ObjectWaiter * t = w ;
ObjectWaiter * u = NULL ;
while (t != NULL) {
guarantee (t->TState == ObjectWaiter::TS_CXQ, "invariant") ;
t->TState = ObjectWaiter::TS_ENTER ;
u = t->_next ;
t->_prev = u ;
t->_next = s ;
s = t;
t = u ;
}
_EntryList = s ;
assert (s != NULL, "invariant") ;
} else {
// QMode == 0 or QMode == 2
//周遊cxq中的元素将其加入到_EntryList中,注意此時cxq連結清單的頭元素被指派給EntryList
_EntryList = w ;
ObjectWaiter * q = NULL ;
ObjectWaiter * p ;
//cxq中的元素是通過next屬性串聯起來的,prev屬性沒有,此處周遊加上prev屬性
//當EntryList頭元素被移除了是取next屬性作為EntryList
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 ;
}
}
if (_succ != NULL) continue;
w = _EntryList ;
if (w != NULL) {
guarantee (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
//喚醒w對應的線程
ExitEpilog (Self, w) ;
return ;
}
}
}
void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) {
assert (_owner == Self, "invariant") ;
//Knob_SuccEnabled預設是1,succ表示很有可能占用該鎖的線程
_succ = Knob_SuccEnabled ? Wakee->_thread : NULL ;
ParkEvent * Trigger = Wakee->_event ;
Wakee = NULL ;
//将owner屬性置為NULL
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);
//喚醒目标線程
Trigger->unpark() ;
if (ObjectMonitor::_sync_Parks != NULL) {
//增加計數
ObjectMonitor::_sync_Parks->inc() ;
}
}
6、try_enter / complete_exit
try_enter用于實作Unsafe類的tryMonitorEnter方法,會嘗試擷取鎖,如果擷取失敗則直接傳回false;complete_exit用于釋放目标鎖,在嵌套加鎖的情形下隻需要調用complete_exit一次即可,如果是exit則需要調用多次。
bool ObjectMonitor::try_enter(Thread* THREAD) {
if (THREAD != _owner) {
if (THREAD->is_lock_owned ((address)_owner)) {
//如果該線程已經占有了該鎖,該鎖由輕量級鎖膨脹而來
assert(_recursions == 0, "internal state error");
//修改owner等屬性
_owner = THREAD ;
_recursions = 1 ;
OwnerIsThread = 1 ;
return true;
}
if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
//原子的設定owner屬性,修改失敗
return false;
}
//修改成功
return true;
} else {
//目前線程已經占有該鎖,将記錄嵌套加鎖的計數器加1
_recursions++;
return true;
}
}
intptr_t ObjectMonitor::complete_exit(TRAPS) {
Thread * const Self = THREAD;
assert(Self->is_Java_thread(), "Must be Java thread!");
JavaThread *jt = (JavaThread *)THREAD;
DeferredInitialize();
if (THREAD != _owner) {
if (THREAD->is_lock_owned ((address)_owner)) {
//如果是輕量級鎖膨脹來的
assert(_recursions == 0, "internal state error");
_owner = THREAD ; /* Convert from basiclock addr to Thread addr */
_recursions = 0 ;
OwnerIsThread = 1 ;
}
}
guarantee(Self == _owner, "complete_exit not owner");
intptr_t save = _recursions; // record the old recursion count
//_recursions置為0,即嵌套加鎖的情形下不需要多次調用exit了
_recursions = 0; // set the recursion level to be 0
//釋放該鎖
exit (true, Self) ; // exit the monitor
guarantee (_owner != Self, "invariant");
return save;
}
7、總結
ObjectMonitor維護了三個ObjectWaiter連結清單,分别是cxq連結清單、EntryList連結清單和WaitSet連結清單,對應連結清單中ObjectWaiter的狀态分别是TS_CXQ,TS_ENTER和TS_WAIT。調用enter方法時,如果自旋擷取鎖失敗就會建立一個ObjectWaiter并加入到cxq連結清單中,某個已經擷取鎖的線程調用wait方法會建立一個ObjectWaiter并加入到WaitSet連結清單中,當某個線程調用notify/notifyAll方法“喚醒”該線程時,會将該ObjectWaiter從WaitSet連結清單中移除然後加入到cxq連結清單頭。當某個擷取鎖的線程釋放鎖時,就會喚醒EntryList連結清單頭對應的線程,如果EntryList連結清單為空,則将此時的cxq連結清單中的元素整體轉移到EntryList連結清單中,然後同樣的喚醒EntryList連結清單頭對應的線程,被喚醒後該線程一樣調用enter方法搶占鎖。