Java教程

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

本文主要是介绍掌握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)) {

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 (;

这篇关于掌握Android和Java线程原理下,2021年Android高级面试题总结的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!