首页 > 其他 > 详细

JUC---12深入理解CAS

时间:2020-06-06 23:54:59      阅读:78      评论:0      收藏:0      [点我收藏+]

一、什么是CAS

  Compare and Swap, 翻译成比较并交换,是java.util.concurrent.atomic包下的类里面的CompareAndSet()方法;java.util.concurrent包中借助CAS实现了区别于synchronouse同步锁的一种乐观锁,使用这些类在多核CPU的机器上会有比较好的性能。

二、小例子

  把2020交换为2021,之后获取操作后的值。再重复一次查看效果

public class MyDemo {
    // CAS compareAndSet : 比较并交换!
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        // 期望、更新
        // public final boolean compareAndSet(int expect, int update)
        // 如果我期望的值达到了,那么就更新,否则,就不更新, CAS 是CPU的并发原语!
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());
        atomicInteger.getAndIncrement();
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());
    }
}

  在java.util.concurrent.atomic包下的任意类调用CompareAndSet()方法,都是调用Unsafe类里面的方法,这个类是底层的,Java调用C++操作。

  在调用getAndIncrement()方法后,方法里面调用unsafe.getAndAddInt(this, valueOffset, 1);到Unsafe类里面操作public final int getAndAddInt(Object var1, long var2, int var4)

方法,其中【this---var1,valueOffset---var2,1---var4】,在这个方法里面,通过var5 = this.getIntVolatile(var1, var2);获取内存地址中的值,然后再调用this.compareAndSwapInt(var1, var2, var5, var5 + var4),使其为真。

  缺点:

    1、循环会耗时

    2、一次性只能保证一个共享变量的原子性

    3、ABA问题----就是多线程下,例如有3个线程同时对同一个值(初始值为A)进行CAS操作,其中两个线程:线程1,期望值为A,欲更新的值为B;线程2,期望值为A,欲更新的值为B。当线程1抢先获得CPU时间片,而线程2因为其他原因阻塞了,线程1取值与期望的A值比较,发现相等然后将值更新为B,然后这个时候出现了线程3,期望值为B,欲更新的值为A,线程3取值与期望的值B比较,发现相等则将值更新为A,此时线程2从阻塞中恢复,并且获得了CPU时间片,这时候线程2取值与期望的值A比较,发现相等则将值更新为B,虽然线程2也完成了操作,但是线程2并不知道值已经经过了A->B->A的变化过程。

  如何解决ABA问题:在变量前面加上版本号,每次变量更新的时候变量的版本号都+1,即A->B->A就变成了1A->2B->3A。(这就是乐观锁的思想)
三、利用AtomicReference<V> 类解决ABA
public class MyDemo {
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1, 1);

    // CAS compareAndSet : 比较并交换!
    public static void main(String[] args) {

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp(); // 获得版本号
            System.out.println("a1=>" + stamp);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            atomicStampedReference.compareAndSet(1, 2,
                    atomicStampedReference.getStamp(),
                    atomicStampedReference.getStamp() + 1);
            System.out.println("a2=>" + atomicStampedReference.getStamp());
            System.out.println(atomicStampedReference.compareAndSet(2, 1,
                    atomicStampedReference.getStamp(),
                    atomicStampedReference.getStamp() + 1));
            System.out.println("a3=>" + atomicStampedReference.getStamp());
        }, "a").start();
        

        // 乐观锁的原理相同!
        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp(); // 获得版本号
            System.out.println("b1=>" + stamp);
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicStampedReference.compareAndSet(1, 6,
                    stamp, stamp + 1));
            System.out.println("b2=>" + atomicStampedReference.getStamp());
        }, "b").start();
    }
}

 

JUC---12深入理解CAS

原文:https://www.cnblogs.com/jenne-blog/p/13057684.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!