偏向锁升级为轻量级锁

对象处于偏向锁时,mark word中的偏向锁标记为1,锁标志位为01;下面是分析过jvm源码(biasedLocking.cpp)解析的偏向锁升级流程(忽略一些细节),示例中:线程1当前拥有偏向锁对象,线程2是需要竞争到偏向锁。

  • 线程2来竞争锁对象;
  • 判断当前对象头是否是偏向锁;
  • 判断拥有偏向锁的线程1是否还存在;
  • 线程1不存在,直接设置偏向锁标识为0(线程1执行完毕后,不会主动去释放偏向锁);
  • 使用cas替换偏向锁线程ID为线程2,锁不升级,仍为偏向锁;
  • 线程1仍然存在,暂停线程1;
  • 设置锁标志位为00(变为轻量级锁),偏向锁为0;
  • 从线程1的空闲monitor record中读取一条,放至线程1的当前monitor record中;
  • 更新mark word,将mark word指向线程1中monitor record的指针;
  • 继续执行线程1的代码;
  • 锁升级为轻量级锁;   
  • 线程2自旋来获取锁对象;

上面仍有一个问题,即如何判断线程1已经不存在了?
仍然是分析完jvm源码(thread.cpp)后,得到的如下结论:
(1) 线程执行start时,会将自己写入一个thread_list中,这是一个linked结构,有pre和next节点;
对应源码位置:
void Threads::add(JavaThread* p, bool force_daemon) {
// The threads lock must be owned at this point
assert_locked_or_safepoint(Threads_lock);
// See the comment for this method in thread.hpp for its purpose and
// why it is called here.
p->initialize_queues();
p->set_next(_thread_list);
_thread_list = p;
_number_of_threads++;
oop threadObj = p->threadObj();
bool daemon = true;
// Bootstrapping problem: threadObj can be null for initial
// JavaThread (or for threads attached via JNI)
if ((!force_daemon) && (threadObj == NULL || !java_lang_Thread::is_daemon(threadObj))) {
_number_of_non_daemon_threads++;
daemon = false;
}

p->set_safepoint_visible(true);
ThreadService::add_thread(p, daemon);
// Possible GC point.
Events::log(p, “Thread added: “ INTPTR_FORMAT, p);
}
(2)线程执行完后,会将自己从thread list中清理掉(源码位置: Threads::remove(this));
因此只需判断thread list中是否存在线程1即可,判断源代码(位于 biasedLocking.cpp中 )如下:
bool thread_is_alive = false;
if (requesting_thread == biased_thread) {
thread_is_alive = true;
} else {
for (JavaThread* cur_thread = Threads::first(); cur_thread != NULL; cur_thread = cur_thread->next()) {
if (cur_thread == biased_thread) {
thread_is_alive = true;
break;
}
}
}