CAS / ABA

CAS / ABA

標籤(空格分隔): 操做系統html


1. CAS 解決 Volatile 不保證原子性的問題

/**
 * Atomically increments by one the current value.
 *
 * @return the previous value
 */
public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

Volatile不保證原子性的解決方案, 在其中咱們能夠看到咱們經過atomicInteger.getAndIncrement(), 獲取值而且將其+1, 重點在於this.compareAndSwapInt(var1, var2, var5, var5 + var4) 經過樂觀鎖的方法, 至關於實現了原子性的操做.java

2. CAS 致使的 ABA 問題解決

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * CAS會致使ABA問題:
 *     CAS算法實現一個重要前提須要取出內存中某時刻的數據而且在當下時刻進行比較並替換(Compare And Set), 那麼在這個時間差的時候可能會致使數據的變化.
 *     好比: 一個線程one從內存位置中V中取出A, 這個時候另外一個線程two也從內存中取出A. 此時線程one和two都持有位置V中A的備份, 在這個時候two將A->B->A 並寫入主存當中.
 *     線程one去進行CAS操做的時候, 發現內存中仍然是A, 而後線程one操做成功.
 *
 *   這個問題主要看線程two對中間操做對 線程one有影響沒, 若是有影響的話. 須要解決一下CAS問題.
 */
public class Test {

    private static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);

    public static void main(String[] args) {
        /*         ABA問題產生實例 Start */
        new Thread(()->{
            atomicReference.compareAndSet(100,101);
            atomicReference.compareAndSet(101,100);
        },"t1").start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicReference.compareAndSet(100, 2019)+"\t"+atomicReference.get());
        }).start();
        /* ABA問題產生實例 End */



        /* ABA問題解決實例 Start */
        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t  第一次版本號 : " + atomicStampedReference.getStamp());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t  第二次版本號 : " + atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t  第三次版本號 : " + atomicStampedReference.getStamp());
        }, "t3").start();

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t  第一次版本號 : " + atomicStampedReference.getStamp());
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("是否修改爲功: " + atomicStampedReference.compareAndSet(100, 2019, 1, atomicStampedReference.getStamp() + 1) + "\t 當前的stamp值: " + atomicStampedReference.getStamp());
            System.out.println("當前最新值: " + atomicStampedReference.getReference());
        }, "t4").start();
        /* ABA問題 解決實例 End */

    }
}
相關文章
相關標籤/搜索