CAS操作

文章目录

基本概念

CPU 为了解决并发问题,提供了 CAS 指令(CAS,全称是 Compare And Swap,即"比较并交换")。CAS 指令包含 3个参数:共享变量的内存地址 A、用于比较的值 B 和共享变量的新值 C;并且只有当内存中地址 A 处的值等于 B 时,才能将内存中地址 A 处的值更新为新值 C。作为一条 CPU 指令,CAS 指令本身是能够保证原子性的。

模拟cas操作伪代码:

java 复制代码
int getAndIncrement() {
    int newValue;
    int oldVal;
    do {
        oldVal = value;
        newValue = oldVal + 1;
        // cas前跟cas后读取的值不一样  重试一遍
    } while (oldVal != cas(oldVal, newValue));
    return value;
}


synchronized int cas(int expect, int newValue) {
    // 读取当前值
    int curValue = value;
    // 比较目前count值是否==期望值
    if (curValue == expect) {
        // 如果是,则更新count的值  不相等 说明在执行获取value后 执行cas之前  该值已经被修改了
        // 也就是进入cas之前读到的value值跟进入cas之后读的value值不相等
        value = newValue;
    }
    return curValue;
}

利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法,实现原子操作,其它原子操作都是利用类似的特性完成的。

整个JUC包都是建立在CAS之上的,因此对于synchronized阻塞算法,J.U.C在性能上有了很大的提升。

CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。

常见的CAS操作类

JUC包中的常用原子操作类

java.util.concurrent.atomic包提供了原子操作类:

AtomicIntegerInteger类型的CAS原子操作
AtomicLongLong类型的CAS原子操作
AtomicBooleanBoolean类型的CAS原子操作
AtomicReference:引用类型的CAS原子操作

AtomicInteger为例子,它提供了支持原子操作的方法,包括

java 复制代码
int get() //获取一个值
int getAndSet(int newValue) //获取并设置值
int getAndIncrement() //获取并进行+1操作
int incrementAndGet() //进行+1后获取值
int getAndDecrement() //获取并-1操作
int decrementAndGet() //进行-1操作后在获取

以下代码使用原子性操作,可以确保最后输出的结果是100

java 复制代码
public class Atom_Test {
        private static AtomicInteger i = new AtomicInteger(0);

        public static void main(String[] args) {
            for (int j = 0; j < 100; j++) {
                new Thread() {
                    public void run() {
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                        }
                        i.getAndIncrement();
                    }
                }.start();
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println(i);
        }
    }

CAS操作的优缺点

优点

确保对内存的读-改-写操作都是原子操作执行

缺点

  1. ABA问题
    因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化 则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它 的值没有发生变化,但是实际上却变化了。
    ABA问题的解决思路就是使用版本号。在变量前面 追加上版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。
    从 Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。
java 复制代码
/**
     * Atomically sets the value of both the reference and stamp
     * to the given update values if the
     * current reference is {@code ==} to the expected reference
     * and the current stamp is equal to the expected stamp.
     *
     * @param expectedReference the expected value of the reference
     * @param newReference the new value for the reference
     * @param expectedStamp the expected value of the stamp
     * @param newStamp the new value for the stamp
     * @return {@code true} if successful
     */
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)));
}
  1. 循环时间长开销大
    自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销
  2. 只能保证一个共享变量的原子操作
    当对一个共享变量执行操作时,我们可以使用循 环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子 性,这时候就需要用到synchronized
相关推荐
王小磊学代码11 天前
每天一学(2)
线程池·cas·阻塞队列
慕木兮人可1 个月前
SpringBoot2.0.x旧版集成Swagger UI报错Unable to infer base url...解决办法
java·spring boot·cas·springsecurity·swagger-ui
Hello-Brand3 个月前
高并发下的数据一致性保障(图文全面总结)
分布式·高并发·分布式锁·cas·一致性·aba
星月IWJ4 个月前
cas_ssl
cas
八了个戒5 个月前
单点登陆(SSO)基于CAS实现前后端分离的SSO系统开发「IDP发起」
前端·javascript·cas·大前端·sso
若明天不见6 个月前
【多线程与高并发 四】CAS、Unsafe 及 JUC 原子类详解
java·cas·juc·unsafe·atomic原子类
Hello-Brand7 个月前
Java核心知识体系8:Java如何保证线程安全性
java·cas·并发编程·线程安全性·synchronized·nocas·volatile·final·多线程模型·case
Hello-Brand7 个月前
Java核心知识体系7:线程安全性讨论
java·分布式·并发·线程安全性·原子性·多线程模型·可见性·有序性
玛卡巴咖9 个月前
CAS详解和学透面试必问并发安全问题
职场和发展·并发·cas