并发编程的历史综述与最新进展以及在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的差距,就不知道具体是怎么造成了。。。
Global site tag (gtag.js) - Google Analytics