Java多线程:objectMonitor源码解读(3)
一、Monitor
1. 什么是Monitor
管程Monitor
这个概念是操作系统中的,在操作系统层面对管程的定义是:若干的公共变量,以及能对这些公共变量进行操作的过程 组成的资源管理程序。
通俗的话来说:管程是用来管理公共资源的,并提供了对共享资源同步与互斥的操作。
同步实现方式:由于进程的执行顺序是不确定的,管程通过condition
变量来让进入管程中的进程无法执行的时候自己阻塞自己。
互斥实现方式:在一个时间点最多只能有一个进程能够执行操作,所以当一个进程试图进入一个巳被占用的管程时它应当在管程的入口处等待,因而在管程的入口处应当有一个进程等待队列,称作入口等待队列。
2.为什么引入管程
引入管程主要是解决信号量同步机制的缺点,进程要自备同步操作,这样同步操作分散在各个进程里面,不易管理,同时也对编写代码提升了难度。
二、objectMonitor源码分析
1 变量
在变量中有几个比较重要的:_cxq
和_EntryList
,_cxq
是用于存储没有竞争到锁的线程,_EntryList
是用来存储等待锁的线程。
ObjectMonitor() { // 多线程竞争锁进入时的单向链表 ObjectWaiter * volatile _cxq; //处于等待锁block状态的线程,会被加入到该列表 ObjectWaiter * volatile _EntryList; // _header是一个markOop类型,markOop就是对象头中的Mark Word volatile markOop _header; // 抢占该锁的线程数,约等于WaitSet.size + EntryList.size volatile intptr_t _count; // 等待线程数 volatile intptr_t _waiters; // 锁的重入次数 volatile intptr_ _recursions; // 监视器锁寄生的对象,锁是寄托存储于对象中 void* volatile _object; // 指向持有ObjectMonitor对象的线程 void* volatile _owner; // 处于wait状态的线程,会被加入到_WaitSet ObjectWaiter * volatile _WaitSet; // 操作WaitSet链表的锁 volatile int _WaitSetLock; // 嵌套加锁次数,最外层锁的_recursions属性为0 volatile intptr_t _recursions; }
2. 执行流程
Java
的Monitor
时基于管程来实现的,所以线程进入Monitor
的流程和进程进入管程类似。
若当前线程执行执行完毕也将释放Monitor
并复位变量的值,以便其它线程线程进入Monitor
。
当线程准备进入Monitor
时,首先线程会被加入到_EntryList
队列当中,当某个线程进入到Monitor
后将ObjectMonitor
中的_owner
变量设置为当前线程,同时ObjectMonitor
中的计数器_count
加1。
若持有Monitor
的线程调用wait()
方法,将释放当前持有的Monitor
,_owner
变量恢复为null
,_count
自减1,同时该线程进入_WaitSet
集合中等待被唤醒。
3. 进入Monitor:enter
3.1 代码注释
// 多个线程同时进入此方法 void ATTR ObjectMonitor::enter(TRAPS) { // 获取当前线程的指针 Thread * const Self = THREAD ; void * cur ; // 通过CAS操作抢占锁,也就是设置_owner的值为当前线程,如果CAS成功返回旧的值,如果失败返回新的值,其中 // Self是新值,NULL是旧值。CAS机制当中使用了3个基本操作数: // CAS(B, V, A): 要设置的新值B,内存地址V,旧的预期值A。设置成功后返回旧的预期值A cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ; // 如果cur == NULL则设置成功,说明此时Monitor锁没有被占用 if (cur == NULL) { return ; } // 如果cur == Self则设置失败,说明此时占用Monitor的就是当前线程,此时是重入 if (cur == Self) { // 锁的重入次数加1 _recursions ++ ; return ; } // 轻量级锁膨胀成重量级锁时,将owner设置为lock属性 if (Self->is_lock_owned ((address)cur)) { assert (_recursions == 0, "internal state error"); // 正常轻量级锁膨胀成重量级锁,之前已经获取轻量级锁的线程不需要二次调用enter方法 // 此时再调用enter方法说明是锁嵌套情形,将_recursions置为1 _recursions = 1 ; // 将_owner设置为当前线程 _owner = Self ; OwnerIsThread = 1 ; return ; } // 该Monitor被其他线程占用了,需要抢占 assert (Self->_Stalled == 0, "invariant"); // 记录需要抢占的Monitor指针 Self->_Stalled = intptr_t(this) ; // Knob_SpinEarly默认为1,即为true // TrySpin让当前线程自旋,自旋次数默认可以自适应调整,如果进入安全点同步则退出自旋,返回1表示抢占成功 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") ; //原子的将_count属性加1,表示增加了一个抢占该锁的线程 Atomic::inc_ptr(&_count); EventJavaMonitorEnter event; { //修改Java线程状态为BLOCKED_ON_MONITOR_ENTER,此代码块退出后还原成原来的 JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this); Self->set_current_pending_monitor(this); DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt); if (JvmtiExport::should_post_monitor_contended_enter()) { JvmtiExport::post_monitor_contended_enter(jt, this); } //修改OS线程状态为MONITOR_WAIT,此代码块退出后还原成原来的 OSThreadContendState osts(Self->osthread()); //让当前线程的调用栈帧可以walkable,即可以被遍历,需要记录上一次执行的Java字节码 //然后切换线程的运行状态,从_thread_in_vm切换成_thread_blocked,切换的过程如果进入安全点同步则会被阻塞,此代码块退出将状态从_thread_blocked切换成_thread_in_vm,同样切换过程中如果进入安全点同步则被阻塞 ThreadBlockInVM tbivm(jt); // TODO-FIXME: change the following for(;;) loop to straight-line code. for (;;) { //将线程的_suspend_equivalent属性置为true,该属性表明当前线程处于悬浮状态 jt->set_suspend_equivalent(); //会通过自旋,park等方式不断循环尝试获取锁,直到成功获取锁为止 EnterI (THREAD) ; //ExitSuspendEquivalent默认返回false if (!ExitSuspendEquivalent(jt)) break ; // 等待suspended当前线程的线程 _recursions = 0 ; _succ = NULL ; exit (false, Self) ; jt->java_suspend_self(); } //将关联的ObjectMonitor置为null,表示当前线程已经不在阻塞状态了 Self->set_current_pending_monitor(NULL); } //原子的将count属性减1,表示已经有一个线程成功获取锁 Atomic::dec_ptr(&_count); assert (_count >= 0, "invariant") ; Self->_Stalled = 0 ; // Must either set _recursions = 0 or ASSERT _recursions == 0. assert (_recursions == 0 , "invariant") ; assert (_owner == Self , "invariant") ; assert (_succ != Self , "invariant") ; assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ; DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt); if (JvmtiExport::should_post_monitor_contended_entered()) { JvmtiExport::post_monitor_contended_entered(jt, this); } if (event.should_commit()) { event.set_klass(((oop)this->object())->klass()); event.set_previousOwner((TYPE_JAVALANGTHREAD)_previous_owner_tid); event.set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr())); event.commit(); } if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) { ObjectMonitor::_sync_ContendedLockAttempts->inc() ; } }
3.2 流程梳理
enter
方法用于进入ObjectMonitor
,当线程执行enter
的时候,先通过CAS
去设置_owner
为当前线程,然后根据返回的结果进行不同的处理。
1.如果CAS
返回值是NULL
,说明设置成功了,当前线程成功的进入了ObjectMonitor
了,也就是抢占到锁了。
2.如果CAS
返回值不为NULL,说明当前有线程已经进入了ObjectMonitor
,也就是已经有线程抢占到了锁。
3.判断当前抢占到ObjectMonitor
的线程是否就是当前线程,如果是的话锁嵌套次数加1_recursion++
,然后退出。
4.如果当前抢占到的ObjectMonitor
的线程不是当前线程,就尝试自旋TrySpin
获取锁。
5.如果还是没有获取到锁,就进入到EnterI
方法,进入EnterI
方法之后,还是先尝试自旋TrySping
获取锁,如果获取到了就退出。
6.如果最后还是没获取到,就把当前现场封装成ObjectWaiter
结构体,然后加入到_cxq
队列的头,并且把当前线程挂起。
4. 退出Monitor:exit
4.1 代码注释
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; } } if (_recursions != 0) { _recursions--; TEVENT (Inflated exit - recursive) ; return ; } if ((SyncFlags & 4) == 0) { _Responsible = NULL ; } for (;;) { assert (THREAD == _owner, "invariant"); if (Knob_ExitPolicy == 0) { OrderAccess::release_store_ptr (&_owner, NULL) ; OrderAccess::storeload(); 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() ; 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") ; ObjectWaiter * w = NULL ; int QMode = Knob_QMode ; // 当QMode等于2并且_cxq不等于空,取_cxq第一个ObjectWaiter对象,并调用ExitEpilog方法,该方法 // 会唤醒ObjectWaiter对象的线程 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不等于空,把_cxq队列放入到_EntryList的队尾 if (QMode == 3 && _cxq != NULL) { // 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 ; } 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不等于空,把_cxq队列放入_EntryList的头部 if (QMode == 4 && _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 ; } if (_EntryList != NULL) { q->_next = _EntryList ; _EntryList->_prev = q ; } _EntryList = w ; } // 如果_EntryList队列不为空,就从_EntryList中取一个线程唤醒 w = _EntryList; if (w != NULL) { assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ; ExitEpilog (Self, w) ; return ; } // 到这里就是_cxq和_EntryLis都为空,就结束 w = _cxq ; if (w == NULL) continue ; // 再次自旋获取 _cxq的首节点 for (;;) { assert (w != NULL, "Invariant") ; 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") ; // QMode = 1,把_cxq倒叙插入_EntryList,反之正序插入 if (QMode == 1) { 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 { _EntryList = w ; 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 ; } } if (_succ != NULL) continue; // 最后从_EntryList中取首元素唤醒 w = _EntryList ; if (w != NULL) { guarantee (w->TState == ObjectWaiter::TS_ENTER, "invariant") ; ExitEpilog (Self, w) ; return ; } } }
4.2 流程梳理
exit
方法时用于退出ObjectMonitor
,在退出的时候也需要唤醒其它等待的线程,根据QMode
的值来判断如何唤醒。
1.当QMode=2
并且_cxq
不为空,取_cxq
队列首元素,调用ExitEpilog
方法,该方法会唤醒封装成ObjectWaiter
对象的线程,此处会立即返回,后面的代码不会执行了。
2.当QMode=3
并且_cxq
非空,把_cxq
队列放入到_EntryList
的尾部。
3.当QMode=4
并且_cxq
非空,把_cxq
队列放入到_EntryList
的头部。
当上述条件都不满足的时候,就判断_EntryList
。
4.如果_EntryList
的不为空,就取一个线程调用ExitEpilog
方法,该方法会唤醒封装成ObjectWaiter
对象的线程,然后立即返回。
5.如果_EntryList
的为空,就再次判断_cxq
是否为空,如果为空的话就自旋继续取。
6.如果_EntryList
的为空,_cxq
不为空,根据QMode
的值,将_cxq
插入_EntryList
,如果QMode=1
将cxq
倒叙插入_EntryList
中;如果QMode!=1将cxq
插入_EntryList
中。
7.最后再从_EntryList
中取出来执行ExitEpilog
方法,唤醒线程。
5. 线程进入等待:wait
5.1 代码注释
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 () ; // 判断当前ObjectMonitor的_owner是不是当前线程 CHECK_OWNER(); EventJavaMonitorWait event; // 如果线程中断了,且没有未处理的异常 if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) { 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") ; Self->_Stalled = intptr_t(this) ; jt->set_current_waiting_monitor(this); // 把当前线程封装成ObjectWaiter结构体 ObjectWaiter node(Self); // 并且设置状态为TS_WAIT node.TState = ObjectWaiter::TS_WAIT; Self->_ParkEvent->reset(); OrderAccess::fence(); // 获取_WaitSetLock锁 Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ; // 将当前线程加入到Wait队列中 AddWaiter (&node) ; // 释放_WaitSetLock锁 Thread::SpinRelease (&_WaitSetLock) ; if ((SyncFlags & 4) == 0) { _Responsible = NULL ; } intptr_t save = _recursions; // 等待线程数+1 _waiters++; _recursions = 0; // 调用exit方法,退出当前ObjectMonitor,让其它线程抢占 exit (true, Self) ; guarantee (_owner != Self, "invariant") ; int ret = OS_OK ; int WasNotified = 0 ; { OSThread* osthread = Self->osthread(); OSThreadWaitState osts(osthread, true); { ThreadBlockInVM tbivm(jt); jt->set_suspend_equivalent(); if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) { } else // 挂起当前线程 if (node._notified == 0) { if (millis _ParkEvent->park () ; } else { ret = Self->_ParkEvent->park (millis) ; } } // 如果当前线程从park状态被晃醒了 if (ExitSuspendEquivalent (jt)) { jt->java_suspend_self(); } } // 如果线程中断,或者等待超时 则线程的状态就是TS_WAIT if (node.TState == ObjectWaiter::TS_WAIT) { Thread::SpinAcquire (&_WaitSetLock, "WaitSet - unlink") ; // 再次校验线程状态 if (node.TState == ObjectWaiter::TS_WAIT) { // 把线程从WaitSet队列中移除 DequeueSpecificWaiter (&node) ; 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 ; 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 ; // 如果线程是TS_RUN 则重新去获取锁 if (v == ObjectWaiter::TS_RUN) { enter (Self) ; } else { 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") ; } jt->set_current_waiting_monitor(NULL); guarantee (_recursions == 0, "invariant") ; _recursions = save; _waiters--; assert (_owner == Self , "invariant") ; assert (_succ != Self , "invariant") ; assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ; if (SyncFlags & 32) { OrderAccess::fence() ; } if (!WasNotified) { if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) { TEVENT (Wait - throw IEX from epilog) ; THROW(vmSymbols::java_lang_InterruptedException()); } } }
5.2 流程梳理
objectMonitor::wait
方法是用来让线程释放当前锁,并挂起当前线程的。
1.线程线程封装成ObjectWaiter
结构体。
2.然后将ObjectWaiter
加入到WaitSet
队列中。
3.挂起当前线程,并且释放objectMonitor。
4.如果线程被中断了,或者被notify
唤醒了,通过enter
方法竞争锁。
6. 唤醒等待线程:notify
6.2 代码注释
void ObjectMonitor::notify(TRAPS) { // 检查当前线程的状态 CHECK_OWNER(); // 如果等待队列为空,直接返回 if (_WaitSet == NULL) { TEVENT (Empty-Notify) ; return ; } DTRACE_MONITOR_PROBE(notify, this, object(), THREAD); int Policy = Knob_MoveNotifyee ; // 获取&_WaitSetLock锁 Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ; // 从WaitSet中取出第一个元素 ObjectWaiter * iterator = DequeueWaiter() ; if (iterator != NULL) { TEVENT (Notify1 - Transfer) ; guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ; guarantee (iterator->_notified == 0, "invariant") ; if (Policy != 4) { // 设置状态为enter iterator->TState = ObjectWaiter::TS_ENTER ; } iterator->_notified = 1 ; Thread * Self = THREAD; 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") ; } // Policy == 0 将 ObjectWaiter放到_EntryList的头部 // 如果_EntryList 为空 就构建一个 if (Policy == 0) { // prepend to EntryList if (List == NULL) { iterator->_next = iterator->_prev = NULL ; _EntryList = iterator ; } else { List->_prev = iterator ; iterator->_next = List ; iterator->_prev = NULL ; _EntryList = iterator ; } } else // Policy == 1 将 ObjectWaiter放到_EntryList的尾部 if (Policy == 1) { if (List == NULL) { iterator->_next = iterator->_prev = NULL ; _EntryList = iterator ; } else { 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 // Policy == 2 // 如果_EntryList 为空就放到_EntryList // 否则就放到 _cxq 的头 if (Policy == 2) { // prepend to 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 // Policy == 3 // 将 ObjectWaiter放到_cxq的尾部 if (Policy == 3) { 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 { // 将等待的线程直接唤醒 ParkEvent * ev = iterator->_event ; iterator->TState = ObjectWaiter::TS_RUN ; OrderAccess::fence() ; ev->unpark() ; } // 修改线程状态,记录锁竞争开始 if (Policy wait_reenter_begin(this); } } // 释放&_WaitSetLock 锁 Thread::SpinRelease (&_WaitSetLock) ; if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) { ObjectMonitor::_sync_Notifications->inc() ; } }
6.3 流程梳理
notify
是通过ObjectMonitor::notify
实现的,notifyAll
和ObjectMonitor::notify
类似,只不过是循环处理。
1.如果当前_WaitSet
为空直接返回。
2.如果不为空从_WaitSet
中取出第一个线程,根据Policy来决定线程放入到那个队列中。
3.Policy = 0
,放入到_EntryList
队列的排头。
4.Policy = 1
,放入到_EntryList
队列的末尾。
5.Policy = 2
,放入到_EntryList
为空就放到_EntryList
,否则就放到_cxq
排头位置。
6.Policy = 3
,放入到_cxq
队列末尾。
二、Java中的Monitor
1. 如何关联objectMonitor
在Java
中由于多个线程同时访问公共资源会造成线程安全问题,为了解决线程安全问题,Java
提供了同步机制,互斥锁机制保证了同一时刻只有一个线程能访问共享资源,这个机制就是基于Monitor
,Java
中每个对象在实例化的时候都会生成一个Monitor
对象与之一一对应。
在JVM
中Monitor
机制是基于C++
实现的,每一个Monitor
都有一个objectMonitor
对象。
Java
中的synchronized
重量级锁、wait
、notify
都是通过Monitor
来实现的。
2.下载openjdk
访问官网openjdk
选择对应的版本,这里是8
选择具体的版本
点击下载
objectMonitor.cpp
的位置在openjdk\hotspot\src\share\vm\runtime\objectMonitor.cpp
目录下。
3. 相关问题回答
3.1 notify 是随机唤醒线程的吗?
结论:不是
根据objectMonitor
的notify
的源码可知,notify
唤醒线程的时候是从等待队列WaitSet
中获取第一个线程来唤醒的。
3.2 notify唤醒的线程一定能获取到锁吗?
结论:不是
notify
唤醒的线程根据Policy
的值,把线程加入到_EntryList
或者cxq
,调用notify
的线程退出的时候执行exit
方法,然后根据QMode
的值决定从_EntryList
或者cxq
中取出线程。
3.3 wait和sleep的区别
结论:wait
会释放锁,sleep
不会
根据wait
的源码,线程调用wait
的时候会调用exit
方法,释放当前objectMonitor
。