并发编程的历史综述与最新进展以及在HotSpot中的具体实现
ZHH2009
2014-08-04
占楼......
|
|
ZHH2009
2014-08-04
占楼......
|
|
ZHH2009
2014-08-04
占楼......
|
|
fh63045
2014-08-04
ZHH2009 写道 占楼......
i++ |
|
rink1969
2014-08-04
要不楼主先抛个问题出来吧
否则不知道该从何说起啊 |
|
ZHH2009
2014-08-04
rink1969 写道 要不楼主先抛个问题出来吧
否则不知道该从何说起啊 你对哪一块理解比较深就直接写好发出来吧,然后我再整理,把所有东西按顺序串起来 |
|
nijiaben
2014-08-04
我先说一下BiasedLocking::revoke_and_rebias这个方法里的一点理解
BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint"); // 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) { // We are probably trying to revoke the bias of this object due to // an identity hash code computation. Try to revoke the bias // without a safepoint. This is possible if we can successfully // compare-and-exchange an unbiased header into the mark word of // the object, meaning that no other thread has raced to acquire // the bias of the object. 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; } } else if (mark->has_bias_pattern()) { Klass* k = Klass::cast(obj->klass()); markOop prototype_header = k->prototype_header(); if (!prototype_header->has_bias_pattern()) { // This object has a stale bias from before the bulk revocation // for this data type occurred. It's pointless to update the // heuristics at this point so simply update the header with a // CAS. If we fail this race, the object's bias has been revoked // by another thread so we simply return and let the caller deal // with it. 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()) { // The epoch of this biasing has expired indicating that the // object is effectively unbiased. Depending on whether we need // to rebias or revoke the bias of this object we can do it // efficiently enough with a CAS that we shouldn't update the // heuristics. This is normally done in the assembly code but we // can reach this point due to various points in the runtime // needing to revoke biases. if (attempt_rebias) { assert(THREAD->is_Java_thread(), ""); markOop biased_value = mark; 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 { 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 = Klass::cast(obj->klass()); markOop prototype_header = k->prototype_header(); if (mark->biased_locker() == THREAD && prototype_header->bias_epoch() == mark->bias_epoch()) { // A thread is trying to revoke the bias of an object biased // toward it, again likely due to an identity hash code // computation. We can again avoid a safepoint in this case // since we are only going to walk our own stack. There are no // races with revocations occurring in other threads because we // reach no safepoints in the revocation path. // Also check the epoch because even if threads match, another thread // can come in with a CAS to steal the bias of an object that has a // stale 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(); } 上述代码中的update_heuristics的方法真正作用主要是当cas失败达到一定次数之后来决定是否批量偏向或者去偏向,那执行到HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias)的时机是什么?我稍微做下总结,有这么几种情况: 1.对象不是偏向模式 2.对象是偏向模式但是epoch过期了,如下两种情况下才会执行到这里 2.1.打算重偏向,但是偏向了另外的线程 2.2.打算撤销偏向,没经过任何gc,但是两个线程都执行了update_heuristics最近的那个else里的代码,那么一个cas成功了,一个失败了,失败的那个也会接下来执行update_heuristics,另外应该不存在经过gc导致age变化而cas失败的情况,因为经过了gc,那递增age也是应用在新对象上的,针对这点我觉得可以展开讨论下 以上是我的一点理解,不知道是否还有别的情况漏掉的,欢迎补充 |
|
ZHH2009
2014-08-06
@nijiaben
对src\share\vm\runtime\mutex.cpp的实现了解得多么,可以先讲一下它。 这个根据不同的os也会有些差异,比如在Windows中用到了事件。 |
|
ZHH2009
2014-08-08
HotSpot JVM在Windows x86实现full、load、store fence分别用了【lock add dword ptr [esp], 0】、【mov eax, dword ptr [esp]】、【volatile jint local_dummy = 0】来实现,让我很困惑,Intel x86不是有SFENCE和LFENCE指令吗?
|
|
rink1969
2014-08-11
ZHH2009 写道 HotSpot JVM在Windows x86实现full、load、store fence分别用了【lock add dword ptr [esp], 0】、【mov eax, dword ptr [esp]】、【volatile jint local_dummy = 0】来实现,让我很困惑,Intel x86不是有SFENCE和LFENCE指令吗?
看了一些资料,可能有两个原因: 1、lock更通用,fence指令可能比较老的cpu不支持 2、我看openjdk6里有一句注释说mfenc性能有时比lock还要差 这个没仔细研究过,但是我觉得fence指令的好处是控制更精细(分了sfence和lfence)。但是对于这里的场景,实际需要的是mfence(等于sfence+lfence),这个在效果上跟lock是一样的,所以性能应该是差不多的。 看到有人贴了个测试数据: lock cmpxchg - 100 cycles mfence - 104 cycles 这4个cycles的差距,就不知道具体是怎么造成了。。。 |