[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends-ml 12415] AtomicLong の実装に ついて



高橋(徹)です。

読書会の時の宿題で、java.util.concurrent.atomic.AtomicLongクラスの
実装を調査しました。
CPUレベルでどのように実現しているかについて、AtomicLongの
incrementAndGetメソッドをとっかかりに調べました。
対象はJava SE 6 (Mustang b91)ベースです。

public final long incrementAndGet() {
    for(;;) {
        long current = get();
        long next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}
という実装で、現在値を非同期ブロックで取得後、インクリメントした値を
算出し、compareAndSetメソッドでアトミックに変更を試みています。試みに
失敗してもビジーループでコンテクストスイッチを発生させずに再試行して
います。

さて、compareAndSetメソッドの実装を追います。

public final boolean compareAndSet(long expect, long update) {
  return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}

unsafeなるオブジェクトは、sun.misc.Unsafeクラスで、compareAndSwapLong
メソッドはnativeメソッドとして宣言されています。

今度は、nativeコードのhotspot/src/share/vm/prims/unsafe.cppを見ると
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapLong(
    JNIEnv *env, jobject unsafe, jobject obj, jlong offset,
    jlong e, jlong x))
    :(中略)
    if (VM_Version::supports_cx8())
      return (jlong)(Atomic::cmpxchg(x, addr, e)) == e;
    else
      jboolean success = false;
      ObjectLocker ol(p, THREAD);
      if (*addr == e) { *addr = x; success = true; }
      return success;
}

となっており、compare and exchangeをサポートしていればそれを呼び出し、
サポートしていなければロックを獲得して入れ替えを行っています。

Atomic::cmpxchgの先はインラインアセンブリで記述されており、
Windows i486では、cmpxcg8b命令
Solaris SPARCでは、casx命令
を使用しています。

Java Concurrency in Practiceの著者 Brian Goetzが執筆した以下の記事
IBM developerWorks:Javaの理論と実践 アトミックで行く
が参考になります。
http://www-06.ibm.com/jp/developerworks/java/041203/j_j-jtp11234.html

--
TAKAHASHI,Toru
torutk@xxxxxxxxxxxx