CAS算法

2020-11-03  本文已影响0人  因你而在_caiyq

原创文章,转载请注明原文章地址,谢谢!

CAS(Compare And Swap)
Unsafe
AtomicInteger.getAndAddInt()源码
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;
}

Unsafe类中的compareAndSwapInt,是一个本地方法,该方法的实现位于unsafe.cpp中。

CAS的缺点
解决ABA问题

ABA问题演示

public class Test {
    private static AtomicInteger index = new AtomicInteger(10);
    public static void main(String[] args) {
        new Thread(() -> {
            index.compareAndSet(10, 11);
            index.compareAndSet(11, 10);
            System.out.println(Thread.currentThread().getName() + " 10->11->10");
        }, "张三").start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
                boolean result = index.compareAndSet(10, 12);
                System.out.println(Thread.currentThread().getName() + " 执行结果:" + result + " 修改后的值是:" + index.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "李四").start();
    }
}

执行结果是

张三 10->11->10
李四 执行结果:true 修改后的值是:12

使用AtomicStampedReference解决ABA问题

public class Test {
    private static AtomicInteger index = new AtomicInteger(10);
    private static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(10, 1);
    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " 第1次版本号:" + stampedReference.getStamp());
            stampedReference.compareAndSet(10, 11, stampedReference.getStamp(), stampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + " 第2次版本号:" + stampedReference.getStamp());
            stampedReference.compareAndSet(11, 10, stampedReference.getStamp(), stampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + " 第3次版本号:" + stampedReference.getStamp());
        }, "张三").start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + " 第1次版本号:" + stampedReference.getStamp());
                boolean result = stampedReference.compareAndSet(10, 12, stampedReference.getStamp(), stampedReference.getStamp() + 1);
                System.out.println(Thread.currentThread().getName() + " 修改是否成功:" + result + " 当前版本号是:" + stampedReference.getStamp());
                System.out.println(Thread.currentThread().getName() +  " 当前实际值是:" + stampedReference.getReference());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "李四").start();
    }
}

执行结果是

张三 第1次版本号:1
张三 第2次版本号:2
张三 第3次版本号:3
李四 第1次版本号:3
李四 修改是否成功:true 当前版本号是:4
李四 当前实际值是:12
compareAndSet方法
public boolean compareAndSet(V   expectedReference,
                             V   newReference,
                             int expectedStamp,
                             int newStamp) {
    Pair<V> current = pair;
    return
            expectedReference == current.reference &&
                    expectedStamp == current.stamp &&
                    ((newReference == current.reference &&
                            newStamp == current.stamp) ||
                            casPair(current, Pair.of(newReference, newStamp)));
}

博客内容仅供自已学习以及学习过程的记录,如有侵权,请联系我删除,谢谢!

上一篇 下一篇

猜你喜欢

热点阅读