在java虚拟机中的方法同步synchronized,是通过使用monitorenter和monitorexit这两个操作码,当虚拟机遇到monitorenter的时候,它会获得栈中objectref所引用的对象的锁。如果线程已经拥有那个对象的锁,锁的计数器加1,线程中每个monitorexit会引起计数器减1,当计数器为0时候,监视器就释放了。
先看看openjdk中的monitorenter代码(bytecodeInterpreter.cpp)
{
if (entry != NULL) { //获取一个空闲的监视器
entry->set_obj(lockee);
markOop displaced = lockee->mark()->set_unlocked();
entry->lock()->set_displaced_header(displaced);
if (Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced) {
if (THREAD->is_lock_owned((address) displaced->clear_lock_bits())) {
entry->lock()->set_displaced_header(NULL);
} else {
CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
}
}
UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
} else { //监视器为空,重试
istate->set_msg(more_monitors);
UPDATE_PC_AND_RETURN(0); // Re-execute
}
}
看一下InterpreterRuntime::monitorenter,
void InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem){
.......
Handle h_obj(thread, elem->obj());
ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
}
slow_enter调用下面的inflate
ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object) {
for (;;) {
const markOop mark = object->mark() ;
/*
mark有几种状态,inflated直接返回,Stack-locked转换为inflated,
INFLATING 不断等待直到完成,Neutral 锁升级?
*/
//inflated 状态
if (mark->has_monitor()) { //已经获得锁,直接返回
ObjectMonitor * inf = mark->monitor() ;
return inf ;
}
if (mark == markOopDesc::INFLATING()) {
ReadStableMark(object) ; //不断检测,超过一定次数睡眠
continue ;
}
//stack locked 状态
if (mark->has_locker()) {
ObjectMonitor * m = omAlloc (Self) ;
markOop cmp = (markOop) Atomic::cmpxchg_ptr (markOopDesc::INFLATING(), object->mark_addr(), mark) ; //将object->mark_addr()和mark比较,如果这两个值相等,则将object->mark_addr()改成markOopDesc::INFLATING(),值比较相等返回是mark,不相等返回的是object->mark_addr(), 比较和赋值是一个原子操作
if (cmp != mark) { //不断检测值,自旋锁的用法
omRelease (Self, m) ;
continue ; // 重新进行循环
}
markOop dmw = mark->displaced_mark_helper() ;
m->set_header(dmw) ; //设置mark->has_monitor()?也就是inflated 状态
...............
return m ;
}
//Neutral状态
m->set_header(mark);
if (Atomic::cmpxchg_ptr (markOopDesc::encode(m), object->mark_addr(), mark) != mark) {//在此又做了一次检测,到底是何目的?
continue ;
}
............
if (_sync_Inflations != NULL) _sync_Inflations->inc() ; //增加计数
return m ;
}
}
整个获取锁的过程十分复杂,大大超出我的预料,大概是为了避免死锁这些,所以才设计了这么复杂,象是采用锁升级这种技术,锁的这几种状态是干什么用的,现在还弄不很清楚。