CAS(Compare And Swap) 算法

Posted oaks

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CAS(Compare And Swap) 算法相关的知识,希望对你有一定的参考价值。

CAS 也叫自旋锁,用来保证操作的一致性,比如用2个线程同时对一个变量累加1000,000次,得到的结果可能比2000,000少:

package juc.test.cas;

import org.junit.Test;

import java.util.concurrent.CountDownLatch;

public class NonAtomicTest {

    static long var = 0 ;
    final int totalThread = 2;
    final long timesEveryThread = 1000000;
    @Test
    public void testAtomicLong(){

        CountDownLatch cdl = new CountDownLatch(totalThread);  // thread count

        for (int j = 0; j < totalThread; j++) {
            new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < timesEveryThread; i++) {
                        var = var + 1;
                    }
                    cdl.countDown();
                }
            }.start();
        }

        try {
            cdl.await();  // wait for all thread return
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(var);
    }
    
}

输出:

1259956

其中的原因有可能是因为他们读取的值一样,计算的结果也一样,而我们希望的结果是一个线程的操作是基于上次计算的结果,CAS可以保证,它的执行流程如图:
技术图片

值得一提的是,“比较(Compare)”和“交换(Swap)” 这两个操作需要合并为一个原子操作并加锁,也就是当有一个线程在进行cmpxchg时其他线程需要等待,防止出现2个线程同时compare发现都ok,然后都替换,比如两个线程都对i加1,i初始化为0,它们同时读取到i为0,并计算得到结果1,并且同时进行compare发现都是前值和现值都是0,很match,然后俩线程都写入1;加上一把锁,即使这俩线程同时读取到i为0,进行compare时必须有先后顺序,就可以保证操作的一致性了。

Java的原子类AtomicInteger等是利用CAS算法实现的,例程的CAS版:

package juc.test.cas;

import org.junit.Test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;

// See also ./hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp:93
public class AtomicTest {


    final int totalThread = 2;
    final long timesEveryThread = 1000000;
    @Test
    public void testAtomicLong(){
        AtomicLong var = new AtomicLong() ;
        CountDownLatch cdl = new CountDownLatch(totalThread);

        for (int j = 0; j < totalThread; j++) {
            new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < timesEveryThread; i++) {
                        var.getAndIncrement();
                    }
                    cdl.countDown();
                }
            }.start();

        }

        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(var.get());
    }

}

输出:

2000000

以上是关于CAS(Compare And Swap) 算法的主要内容,如果未能解决你的问题,请参考以下文章

CAS(Compare and swap)比较并交换算法解析

CAS(Compare and swap)比较并交换算法解析

CAS(Compare and swap)比较并交换算法解析

非阻塞同步算法与CAS(Compare and Swap)无锁算法

CAS(Compare and Swap)理解

Java多线程和并发,CAS(Compare and Swap)