私が使用していますAtomicBoolean
強制するためにvolatile
、スレッド間の可視性を。1つのスレッドが別のスレッドが唯一それを読んでいる、値を更新しています。
現在の値があると言いますtrue
。今言う書き込みスレッドは、その値を設定し、true
再び:
final AtomicBoolean b = new AtomicBoolean(); // shared between threads
b.set(true);
// ... some time later
b.set(true);
この「ダミー」の後set(true)
、パフォーマンスの低下は時にあり、読み取りスレッドの呼び出しget()
?ん読み取りスレッドは再読み込みする必要がありますし、値をキャッシュ?
その場合は、書き込みスレッドが行っている可能性があり:
b.compareAndSet(false, true);
この方法では、読み取りスレッドが唯一の真の変化を無効にする必要があります。
public final boolean compareAndSet(boolean expect, boolean update) {
int e = expect ? 1 : 0;
int u = update ? 1 : 0;
return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}
compareAndSwapInt()
すでにネイティブであります:
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");
oop p = JNIHandles::resolve(obj);
jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END
どこにAtomic::cmpxchg
されて生成されたとして、JVMの実行開始時にどこかを
address generate_atomic_cmpxchg() {
StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg");
address start = __ pc();
__ movl(rax, c_rarg2);
if ( os::is_MP() ) __ lock();
__ cmpxchgl(c_rarg0, Address(c_rarg1, 0));
__ ret(0);
return start;
}
cmpxchgl()
x86のコードは、(私はここで1つをコピーしませんので、それは、あまりにも長く、レガシーコードパスを持っている)生成します。
InstructionMark im(this);
prefix(adr, reg);
emit_byte(0x0F);
emit_byte(0xB1);
emit_operand(reg, adr);
0F
B1
本当にあるCMPXCHG
操作。あなたは上記のコードを確認した場合、if ( os::is_MP() ) __ lock();
発するLOCK
マルチプロセッサマシン上のプレフィックスを(私はちょうど引用飛ばしてみましょうlock()
、それは単一発するF0
ので、事実上どこでも、バイト)。
そしてとしてCMPXCHG
ドキュメント言います:
この命令は、命令がアトミックに実行できるようにするためにLOCKプリフィックスを使用することができます。プロセッサのバスへのインタフェースを簡素化するために、デスティネーション・オペランドは、比較の結果に関係なく書き込みサイクルを受けます。デスティネーションオペランドの比較が失敗した場合に書き戻されます。そうでない場合は、ソース・オペランドは、先に書き込まれます。(プロセッサは、ロックされた書き込みを生じることなくロックされた読み取りを作り出すことはありません。)
だから、マルチプロセッサのx86マシン上で、NOP-CASは、キャッシュ・ラインに影響を与え、書き込みを行います。(強調は私が追加されました)