ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2022-01-26 17:58:43  阅读:198  来源: 互联网

标签:面试题 obj lock self mark 线程 Java Android NULL


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)) {

tty->print_cr(" Revoked bias of object biased toward dead thread");

}

return BiasedLocking::BIAS_REVOKED;

}

// 线程还存活则遍历线程栈中所有的Lock Record

GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(biased_thread);

BasicLock* highest_lock = NULL;

for (int i = 0; i < cached_monitor_info->length(); i++) {

MonitorInfo* mon_info = cached_monitor_info->at(i);

// 如果能找到对应的Lock Record说明偏向的线程还在执行同步代码块中的代码

if (mon_info->owner() == obj) {

if (TraceBiasedLocking && Verbose) {

tty->print_cr(" mon_info->owner (" PTR_FORMAT “) == obj (” PTR_FORMAT “)”,

(void *) mon_info->owner(),

(void *) obj);

}

// 需要升级为轻量级锁,直接修改偏向
线程栈中的Lock Record

markOop mark = markOopDesc::encode((BasicLock*) NULL);

highest_lock = mon_info->lock();

highest_lock->set_displaced_header(mark);

}

}

if (highest_lock != NULL) {

// 修改第一个Lock Record为无锁状态,然后将obj的mark word设置为指向该Lock Record的指针

highest_lock->set_displaced_header(unbiased_prototype);

// Reset object header to point to displaced mark

obj->set_mark(markOopDesc::encode(highest_lock));

assert(!obj->mark()->has_bias_pattern(), “illegal mark state: stack lock used bias bit”);

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

tty->print_cr(" Revoked bias of currently-locked object");

}

} else {

// 走到这里说明偏向线程已经不在同步块中了

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

tty->print_cr(" Revoked bias of currently-unlocked object");

}

if (allow_rebias) {

//设置为匿名偏向状态

obj->set_mark(biased_prototype);

} else {

// 将mark word设置为无锁状态

obj->set_mark(unbiased_prototype);

}

}

return BiasedLocking::BIAS_REVOKED;

}

了解了偏向锁的加锁流程,再接着看自旋锁和重量级锁的加锁流程slow_enter。

轻量级锁加锁流程

void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {

markOop mark = obj->mark();

assert(!mark->has_bias_pattern(), “should not see bias pattern here”);

//是否为无锁状态

if (mark->is_neutral()) {

//如果是无锁状态,通过cas加轻量级锁,cas成功则表示加锁成功

lock->set_displaced_header(mark);

if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {

TEVENT (slow_enter: release stacklock) ;

return ;

}

} else

//如果是有锁状态,判断是否是同一把锁,如果是,则直接进入临界区

if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {

assert(lock != mark->locker(), “must not re-lock the same lock”);

assert(lock != (BasicLock*)obj->mark(), “don’t relock with same BasicLock”);

lock->set_displaced_header(NULL);

return;

}

lock->set_displaced_header(markOopDesc::unused_mark());

//如果上面两种状态都不满足,说明出现了锁的竞争情况,轻量级锁需要膨胀成重量级锁

ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);

}

slow_enter会判断是否是无锁,如果是,则通过CAS进行轻量级锁加锁则,如果有锁,则判断是否是同意把锁,如果是,也可以直接进入临界区,如果不是,轻量级锁需要调用flate函数膨胀成重量级锁,膨胀成重量级锁后,执行enter方法。我们先看看膨胀过程。

轻量级锁膨胀过程

我们接着看inflate是如何进行膨胀的

ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object) {

for (;

标签:面试题,obj,lock,self,mark,线程,Java,Android,NULL
来源: https://blog.csdn.net/m0_66265031/article/details/122706436

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有