JAva理解CAS

2569 ワード

JDK 5以前にJava言語はsynchronizedキーワードによって同期が保証されていたため、ロックが発生した(後述する章ではロックについても言及する).
ロックメカニズムには次の問題があります.
(1)マルチスレッド競合において、ロックのロック、ロックの解除は、比較的多くのコンテキスト切替およびスケジューリング遅延を引き起こし、パフォーマンスの問題を引き起こす.
(2)1つのスレッドがロックを保持すると、このロックが必要な他のすべてのスレッドが停止します.
(3)優先度の高いスレッドが優先度の低いスレッドのロック解除を待つと、優先度が逆転し、パフォーマンスリスクが発生します.
volatileは良いメカニズムですが、volatileは原子性を保証できません.したがって、同期については最終的にロックメカニズムに戻ります.
独占ロックは悲観的なロックであり、synchronizedは独占ロックであり、ロックが必要な他のすべてのスレッドが停止し、ロックがあるスレッドがロックを解除するのを待つことになります.もう一つのより効果的なロックは楽観的なロックです.楽観ロックとは、ロックをかけないたびに衝突がないと仮定して操作を完了し、衝突に失敗した場合は成功するまで再試行することです.
CAS操作上の楽観的なロックに使用されるメカニズムはCAS,Compare and Swapである.
CASには3つのオペランド、メモリ値V、古い予想値A、修正する新しい値Bがあります.そして、メモリ値Vは、予想値Aとメモリ値Vとが同時にBに変更された場合にのみ、何もしない.
非ブロックアルゴリズム(nonblocking algorithms)
1つのスレッドの失敗または保留は、他のスレッドの失敗または保留に影響を与えるべきではないアルゴリズムです.
現代のCPUは,共有データを自動的に更新し,他のスレッドの干渉を検出できる特殊な命令を提供しているが,compareAndSet()はこれらをロックの代わりに用いている.
AtomicIntegerを取り出して,ロックなしでデータの正確性を調べる.
private volatile int value;
まず,ロックのないメカニズムではvolatile原語を用いてスレッド間のデータが可視(共有)であることを保証する必要があるとは考えられない.これにより、変数の値が取得されたときに直接読み込むことができます.
public final int get() {
        return value;
    }

     ++i      。

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

ここではCASオペレーションを採用し,メモリからデータを読み出すたびに+1後の結果とCASオペレーションを行い,成功すれば結果を返し,そうでなければ成功するまで再試行する.
compareAndSetはJNIを利用してCPU命令の操作を完了する.
public final boolean compareAndSet(int expect, int update) {   
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

全体的なプロセスは,CPUのCAS命令を利用しながらJNIを用いてJavaの非ブロックアルゴリズムを完成させる.他の原子操作は類似の特性を用いて行われた.
J.U.C全体がCAS上に構築されているため、synchronizedブロックアルゴリズムではJ.U.Cの性能が大幅に向上しています.
CASは爽やかに見えるが「ABA問題」を引き起こす.
CASアルゴリズムは,メモリ内のある時点のデータを取り出すことを重要な前提とし,次の時点で比較して置き換えると,この時間差クラスでデータの変化をもたらす.
例えば、1つのスレッドoneがメモリ位置VからAを取り出すと、別のスレッドtwoもメモリからAを取り出し、twoがいくつかの操作を行ってBになり、twoがV位置のデータをAにすると、スレッドoneがCAS操作を行うとメモリ中がAであることがわかり、後one操作は成功した.スレッドoneのCAS操作は成功したが,このプロセスに問題がないわけではない.チェーンテーブルのヘッダが2回変化した後に元の値に戻った場合、チェーンテーブルが変化していないわけではありません.したがって,前述の原子操作AtomicStampedReference/ATomicMarkableReferenceは有用である.これにより、変化する元素の一対の原子操作が可能になる.