CAS - 原理简介

        CAS是JDK提供的非阻塞原子操作,它通过硬件保证了比较-更新的原子性。它是非阻塞的且自身具有原子性,也就是说CAS效率高、可靠。CAS是一条CPU的原子指令(cmpxchg指令),不会造成所谓的数据不一致问题,Unsafe类提供的CAS方法(如:compareAndSwapXXX)底层实现就是CPU的cmpxchg指令。

        执行cmpxchg指令指令的时候,会判断当前系统是否为多核系统,如果是就给总线加锁,只有一个线程会对总线加锁成功,加锁成功之后会执行cas操作,也就是说CAS的原子性实际上是CPU实现独占的,比起用synchronized重量级锁,这里的排他时间很短,所以多线程情况下性能会比较好。

        CAS,compare and swap的缩写,中文翻译成比较并交换,实现并发算法时常用的一种技术。它包含三个操作数:内存位置、预期原值、更新值。执行CAS操作的时候,将内存位置的值与预期原值进行比较:

  1. 如果匹配,那么处理器会自动将该位置的更新为新值。
  2. 如果不匹配,处理器不做任何操作或者重试,当它重试这种行为我们称之为:自旋。多个线程同时执行CAS操作只会有一个线程成功。

CAS - 原理简介_第1张图片

 

没有CAS之前

        有个Resource资源类,为了保证addNumber()方法中的number++的原子性,我们必须使用synchronized将该方法上锁。

class Resource {
​​​​​​​
    //保证可见性
    volatile Integer number = 0;

    public Integer getNumber() {
        return number;
    }

    //加锁保证原子性
    public synchronized void addNumber() {
        number++;
    }
}

使用CAS

        如果使用AtomicInteger原子整型类,我们就不需要synchronized这样重量级的锁来保证多线程环境下的并发问题导致的问题。

class Resource {

    private AtomicInteger atomicInteger = new AtomicInteger();

    public Integer getAtomicInteger() {
        return atomicInteger.get();
    }

    public void setAtomicInteger() {
        atomicInteger.getAndIncrement();
    }
}

        使用100个线程,每个线程对atomicInteger 进行加100次。逻辑上我们的最终打印的结果应该是:10000。

    //线程数
    private static final Integer THREAD_COUNTS = 100;
    private static final CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNTS);

    public static void main(String[] args) {

        Resource resource = new Resource();

        for (int i = 0; i < THREAD_COUNTS; i++) {
            new Thread(() -> {
                //每个线程加100次
                for (int j = 0; j < 100; j++) {
                    resource.setAtomicInteger();
                }
                countDownLatch.countDown();
            }, "线程:" + i).start();
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("得到最终值:" + resource.getAtomicInteger());
    }

        打印结果:

得到最终值:10000

你可能感兴趣的:(Java并发编程,CAS)