感觉这个源码不是很有营养,今天写的会粗糙一些,主要过一遍方法流程
1、wait()——获取重量级锁
int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
//获得当前线程引用
JavaThread* current = THREAD;
// 等待时间不能小于0
if (millis < 0) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
}
// 返回重量级锁对象
// 如果当前是轻量级锁,则膨胀为重量级锁。如果正在膨胀,则等待。如果已经膨胀完毕,则返回重量级锁对象。
ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_wait);
DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), current, millis);
//进入这里
monitor->wait(millis, true, THREAD); // Not CHECK as we need following code
int ret_code = dtrace_waited_probe(monitor, obj, THREAD);
return ret_code;
}
2、wait()——等待队列
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
JavaThread* current = THREAD;
assert(InitDone, "Unexpectedly not initialized");
CHECK_OWNER(); // Throws IMSE if not owner.
EventJavaMonitorWait event;
// check for a pending interrupt
// 检查打断
if (interruptible && current->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {
if (JvmtiExport::should_post_monitor_waited()) {
JvmtiExport::post_monitor_waited(current, this, false);
}
if (event.should_commit()) {
post_monitor_wait_event(&event, this, 0, millis, false);
}
// 抛出打断异常
THROW(vmSymbols::java_lang_InterruptedException());
return;
}
assert(current->_Stalled == 0, "invariant");
current->_Stalled = intptr_t(this);
current->set_current_waiting_monitor(this);
//创建等待队列节点
ObjectWaiter node(current);
//节点状态设置为TS_WAIT
node.TState = ObjectWaiter::TS_WAIT;
current->_ParkEvent->reset();
//插入万能屏障
OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - add");
//将节点加入到等待队列
AddWaiter(&node);
Thread::SpinRelease(&_WaitSetLock);
_Responsible = NULL;
intx save = _recursions; // record the old recursion count
//等待队列计数+1
_waiters++; // increment the number of waiters
_recursions = 0; // set the recursion level to be 1
//释放重量级锁
exit(current); // exit the monitor
guarantee(owner_raw() != current, "invariant");
int ret = OS_OK;
int WasNotified = 0;
// 获取打断标志
bool interrupted = interruptible && current->is_interrupted(false);
{ // State transition wrappers
OSThread* osthread = current->osthread();
OSThreadWaitState osts(osthread, true);
assert(current->thread_state() == _thread_in_vm, "invariant");
{
ClearSuccOnSuspend csos(this);
ThreadBlockInVMPreprocess<ClearSuccOnSuspend> tbivs(current, csos, true /* allow_suspend */);
//检查打断
if (interrupted || HAS_PENDING_EXCEPTION) {
// Intentionally empty
//检查有没有被notify
} else if (node._notified == 0) {
//miles = 0 ,无限期park,等待别的线程唤醒
if (millis <= 0) {
current->_ParkEvent->park();
} else {
// millis > 0 ,park一定时间
ret = current->_ParkEvent->park(millis);
}
}
}
//到这里说明被唤醒了
if (node.TState == ObjectWaiter::TS_WAIT) {
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - unlink");
if (node.TState == ObjectWaiter::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 == current) _succ = NULL;
WasNotified = node._notified;
if (JvmtiExport::should_post_monitor_waited()) {
JvmtiExport::post_monitor_waited(current, this, ret == OS_TIMEOUT);
if (node._notified != 0 && _succ == current) {
node._event->unpark();
}
}
if (event.should_commit()) {
post_monitor_wait_event(&event, this, node._notifier_tid, millis, ret == OS_TIMEOUT);
}
OrderAccess::fence();
assert(current->_Stalled != 0, "invariant");
current->_Stalled = 0;
assert(owner_raw() != current, "invariant");
ObjectWaiter::TStates v = node.TState;
// 进入重新获取锁的逻辑
// 判断状态,确保这期间状态仍然是RUN
if (v == ObjectWaiter::TS_RUN) {
// 重量级锁获取,这个之前文章说过了
enter(current);
} else {
guarantee(v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant");
// 这个方法简单说就是看看是不是Enter或者CXQ状态,如果是的话尝试自旋获取锁,获取不到就继续park
ReenterI(current, &node);
node.wait_reenter_end(this);
}
...下面的不是很重要 省略了
}
- 简单总结一下wait()流程:
- wait()--->获取重量级锁(当前是轻量级锁则膨胀)--->线程加入等待队列--->释放重量级锁--->线程被挂起--->被唤醒后重新进入获取重量级锁流程
3、exit() 释放锁&EntryList
void ObjectMonitor::exit(JavaThread* current, bool not_suspended) {
// 获取持锁线程
void* cur = owner_raw();
if (current != cur) {
if (current->is_lock_owned((address)cur)) {
// 如果当前线程就是持锁线程
assert(_recursions == 0, "invariant");
//关联轻量级锁持有者
set_owner_from_BasicLock(cur, current); // Convert from BasicLock* to Thread*.
_recursions = 0;
} else {
//如果当前线程不是持锁线程
#ifdef ASSERT
LogStreamHandle(Error, monitorinflation) lsh;
lsh.print_cr("ERROR: ObjectMonitor::exit(): thread=" INTPTR_FORMAT
" is exiting an ObjectMonitor it does not own.", p2i(current));
lsh.print_cr("The imbalance is possibly caused by JNI locking.");
print_debug_style_on(&lsh);
assert(false, "Non-balanced monitor enter/exit!");
#endif
//直接return,非持锁线程不能释放
return;
}
}
if (_recursions != 0) {
_recursions--; // this is simple recursive enter
return;
}
_Responsible = NULL;
#if INCLUDE_JFR
if (not_suspended && EventJavaMonitorEnter::is_enabled()) {
_previous_owner_tid = JFR_THREAD_ID(current);
}
#endif
for (;;) {
assert(current == owner_raw(), "invariant");
//释放锁并清除锁的持有者
release_clear_owner(current);
OrderAccess::storeload();
// 先检查EntryList和cxq是否为空,如果俩者都为空直接return,没有要排队获取锁的线程,什么都不需要做
if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
return;
}
// 如果这个方法结果不为NULL,说明在这期间重量级锁被别的线程抢占获取了,这时也可以return了
if (try_set_owner_from(NULL, current) != NULL) {
return;
}
guarantee(owner_raw() == current, "invariant");
ObjectWaiter* w = NULL;
// 获取EntryList
w = _EntryList;
if (w != NULL) {
assert(w->TState == ObjectWaiter::TS_ENTER, "invariant");
// 唤醒EntryList中头节点
ExitEpilog(current, w);
return;
}
//下面这块代码的作用
//将 _cxq 中的节点转移到 _EntryList 中,然后将 _EntryList 中的节点转换成一个双向链表。
//这样做的目的是将原来在 _cxq 中排队的线程移到 _EntryList 中
//将它们的状态从等待状态(TS_CXQ)改为进入状态(TS_ENTER)。
w = _cxq;
if (w == NULL) continue;
for (;;) {
assert(w != NULL, "Invariant");
ObjectWaiter* u = Atomic::cmpxchg(&_cxq, w, (ObjectWaiter*)NULL);
if (u == w) break;
w = u;
}
assert(w != NULL, "invariant");
assert(_EntryList == NULL, "invariant");
_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;
w = _EntryList;
if (w != NULL) {
guarantee(w->TState == ObjectWaiter::TS_ENTER, "invariant");
//唤醒EntryList中头的节点
ExitEpilog(current, w);
return;
}
}
}
- 简单总结一些流程:执行exit()--->判断线程是否是持锁线程--->进入循环---->释放重量级锁--->进入几种不同模式:
- 1.cxq和entryList都没竞争线程,直接return,不需要后续操作了。
- 2.尝试获取重量级锁时发现已被其他线程抢占,直接return。
- 3.将cxq中的节点转移到EntryList,形成一个双向链表,然后每次从EntryList中取头节点unpark(唤醒)
4、notify()——唤醒等待队列中的线程
void ObjectSynchronizer::notify(Handle obj, TRAPS) {
//获取当前线程
JavaThread* current = THREAD;
//获取加锁对象的markword
markWord mark = obj->mark();
//如果没有膨胀过,说明无竞争,不需要唤醒,直接return
if (mark.has_locker() && current->is_lock_owned((address)mark.locker())) {
// Not inflated so there can't be any waiters to notify.
return;
}
// 获取重量级锁
ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_notify);
// 进入唤醒流程
monitor->notify(CHECK);
}
void ObjectMonitor::notify(TRAPS) {
JavaThread* current = THREAD;
//检查当前线程是否是锁持有者
CHECK_OWNER(); // Throws IMSE if not owner.
//如果等待队列为空,无需唤醒,直接return
if (_WaitSet == NULL) {
return;
}
DTRACE_MONITOR_PROBE(notify, this, object(), current);
//进这里
INotify(current);
OM_PERFDATA_OP(Notifications, inc(1));
}
void ObjectMonitor::INotify(JavaThread* current) {
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - notify");
//这里面取出了等待队列的头节点,并且从队列中移除了头节点
ObjectWaiter* iterator = DequeueWaiter();
//如果头节点不为空
if (iterator != NULL) {
guarantee(iterator->TState == ObjectWaiter::TS_WAIT, "invariant");
guarantee(iterator->_notified == 0, "invariant");
//修改节点状态为ENTER
iterator->TState = ObjectWaiter::TS_ENTER;
//修改其状态为已被notify
iterator->_notified = 1;
iterator->_notifier_tid = JFR_THREAD_ID(current);
//获取EntryList,准备把waitset中的节点放进EntryList
ObjectWaiter* list = _EntryList;
if (list != NULL) {
assert(list->_prev == NULL, "invariant");
assert(list->TState == ObjectWaiter::TS_ENTER, "invariant");
assert(list != iterator, "invariant");
}
// prepend to cxq
if (list == NULL) {
//如果此时EntryList为空,只取出一个节点放入EntryList
//节点前后指针置为空,不能放入其他节点
iterator->_next = iterator->_prev = NULL;
//将节点放入EntryList
_EntryList = iterator;
} else {
// 修改节点状态为CXQ
iterator->TState = ObjectWaiter::TS_CXQ;
for (;;) {
//将waitSet中一个节点放入_cxq
ObjectWaiter* front = _cxq;
iterator->_next = front;
if (Atomic::cmpxchg(&_cxq, front, iterator) == front) {
break;
}
}
iterator->wait_reenter_begin(this);
}
Thread::SpinRelease(&_WaitSetLock);
}
- 简单总结一下流程:
- 1.如果锁是轻量级锁,说明无竞争直接返回
- 2.获取重量级锁
- 3.waitSet如果为空直接返回
- 4.waitSet不为空--->取出waitSet头节点放入EntryList,状态改为ENTER,作为waitSet中第一竞争优先者。
- 5.剩余节点放入cxq,继续等着吧,等待下次锁被释放被转移到EntryList它才能竞争锁。
5、一点总结
EntryList填充时机:notify时EntryList为空情况下waitSet的第一个节点;Exit时cxq中的节点转移
EntryList出队时机:Exit时竞争锁
cxq填充时机:重量级锁竞争,自旋无数次失败后存入;notify时waitSet的第一个节点存入
cxq出队时机:Exit时向EntryList中转移