掌握Android和Java线程原理下,2021年Android高级面试题总结

monitorenter主要根据虚拟机是否开启偏向锁来进行偏向锁加锁,如果没开启,则进行自旋锁或重量级锁加锁。先看偏向锁的加锁流程,它的实现在fast_enter函数。

偏向锁加锁流程

//文件–>\src\share\vm\runtime\synchronizer.cpp

void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {

//判断是否开启了偏向锁

if (UseBiasedLocking) {

//安全检查

if (!SafepointSynchronize::is_at_safepoint()) {

//偏向锁测序或者重偏向逻辑

BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);

if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {

return;

}

} else {

assert(!attempt_rebias, “can not rebias toward VM thread”);

BiasedLocking::revoke_at_safepoint(obj);

}

assert(!obj->mark()->has_bias_pattern(), “biases should be revoked by now”);

}

//如果没有开启偏向锁,还是会走重量级锁的加锁流程

slow_enter (obj, lock, THREAD) ;

}

fast_enter的关键流程在revoke_and_rebias函数中实现,函数中的逻辑主要如下:

  1. 判断markwork是否为偏向锁状态,也就是偏向锁标志位是否为 1,如果为是偏向锁状态,进入下一步检测,如果不是,直接通过CAS进行偏向锁加锁,加锁成功后就可进入临界区执行临界区的字节码;

  2. 如果是偏向锁状态,则检测markwork中ThreadId,如果指向当前线程,则可以直接进入临界区;如果为空,则进入步骤3;如果指向其它线程,进入步骤4;

  3. 通过CAS设置markwork中ThreadId为当前线程ID,如果执行CAS成功,表示偏向锁加锁成功,进入临界区,否则进入步骤4;

  4. 如果执行CAS失败,表示当前存在多个线程竞争锁,撤销偏向锁,执行slow_enter流程。

BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {

// We can revoke the biases of anonymously-biased objects

// efficiently enough that we should not cause these revocations to

// update the heuristics because doing so may cause unwanted bulk

// revocations (which are expensive) to occur.

markOop mark = obj->mark();

if (mark->is_biased_anonymously() && !attempt_rebias) {

//匿名偏向状态,即ThreadId为0以及偏向标志关闭,则需要撤销偏向锁。

markOop biased_value = mark;

markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());

markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);

if (res_mark == biased_value) {

//返回BIAS_REVOKED标志后,fast_enter函数中会接着走slow_enter逻辑

return BIAS_REVOKED;

}

} else if (mark->has_bias_pattern()) {

Klass* k = obj->klass();

markOop prototype_header = k->prototype_header();

if (!prototype_header->has_bias_pattern()) {

//如果关闭偏向锁模式,则需要撤销偏向锁

markOop biased_value = mark;

markOop res_mark = (markOop) Atomic::cmpxchg_ptr(prototype_header, obj->mark_addr(), mark);

assert(!(*(obj->mark_addr()))->has_bias_pattern(), “even if we raced, should still be revoked”);

return BIAS_REVOKED;

} else if (prototype_header->bias_epoch() != mark->bias_epoch()) {

//偏向锁过期

if (attempt_rebias) {

assert(THREAD->is_Java_thread(), “”);

markOop biased_value = mark;

//如果attempt_rebias开启,重新设置过期时间

markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch());

markOop res_mark = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark);

if (res_mark == biased_value) {

return BIAS_REVOKED_AND_REBIASED;

}

} else {

//如果attempt_rebias关闭,则撤销偏向锁

markOop biased_value = mark;

markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());

markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);

if (res_mark == biased_value) {

return BIAS_REVOKED;

}

}

}

}

//更新撤销偏向锁计数,并返回偏向锁撤销次数和偏向次数

HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias);

if (heuristics == HR_NOT_BIASED) {

return NOT_BIASED;

} else if (heuristics == HR_SINGLE_REVOKE) {

//如果要撤销或者重偏向偏向锁的线程是当前线程,则直接撤销当前线程线程的偏向锁

Klass *k = obj->klass();

markOop prototype_header = k->prototype_header();

if (mark->biased_locker() == THREAD &&

prototype_header->bias_epoch() == mark->bias_epoch()) {

ResourceMark rm;

if (TraceBiasedLocking) {

tty->print_cr(“Revoking bias by walking my own stack:”);

}

//撤销偏向锁或者重偏向

BiasedLocking::Condition cond = revoke_bias(obj(), false, false, (JavaThread*) THREAD);

((JavaThread*) THREAD)->set_cached_monitor_info(NULL);

assert(cond == BIAS_REVOKED, “why not?”);

return cond;

} else {

//如果不是当前线程,将方法提交到虚拟机的线程栈中执行

VM_RevokeBias revoke(&obj, (JavaThread*) THREAD);

VMThread::execute(&revoke);

return revoke.status_code();

}

}

assert((heuristics == HR_BULK_REVOKE) ||

(heuristics == HR_BULK_REBIAS), “?”);

//当撤销偏向锁的次数达到阈值,则表示这个对象不适合偏向锁,于是对所有使用了这个对象的线程进行批量撤销或批量重偏

VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD,

(heuristics == HR_BULK_REBIAS),

attempt_rebias);

VMThread::execute(&bulk_revoke);

return bulk_revoke.status_code();

}

接着看revoke_bias函数,是如何撤销或者重偏向锁的

static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread) {

markOop mark = obj->mark();

……

uint age = mark->age();

markOop biased_prototype = markOopDesc::biased_locking_prototype()->set_age(age);

markOop unbiased_prototype = markOopDesc::prototype()->set_age(age);

JavaThread* biased_thread = mark->biased_locker();

if (biased_thread == NULL) {

// 匿名偏向

if (!allow_rebias) {

obj->set_mark(unbiased_prototype);

}

if (TraceBiasedLocking && (Verbose || !is_bulk)) {

tty->print_cr(" Revoked bias of anonymously-biased object");

}

return BiasedLocking::BIAS_REVOKED;

}

// 判断线程是否存活

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;

}

}

}

//如果线程不存活,则将markword设置为匿名偏向锁或者无锁状态

if (!thread_is_alive) {

if (allow_rebias) {

obj->set_mark(biased_prototype);

} else {

obj->set_mark(unbiased_prototype);

}

if (TraceBiasedLocking && (Verbose || !is_bulk)) {

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值