[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