27. 深入理解CAS

简介: 27. 深入理解CAS

深入理解CAS

什么是CAS?

CAS是原子类的一个方法:compareAndSet  CAS是CPU的并发原语,该方法有两个参数,返回类型为布尔值,操作成功返回true,否则返回false

public final boolean compareAndSet(int expect, int update) { //期望,修改
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
package com.wyh.cas;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @program: JUC
 * @description: CAS测试
 * @author: 魏一鹤
 * @createDate: 2022-03-13 20:26
 **/
//什么是CAS? 原子类的一个方法compareAndSet 比较并交换
public class CASDemo {
public static void main(String[] args){
//创建原子类 初始值为2022
        AtomicInteger atomicInteger=new AtomicInteger(2021);
//public final boolean compareAndSet(int expect, int update)  期望 更新
        //如果期望的值达到了,就更新值,否则就不更新 返回布尔值
        System.out.println(atomicInteger.compareAndSet(2021,1999));//true
        //输出结果
        System.out.println(atomicInteger.get()); //1999
//由于当前值已经为1999,无法达到2021 所以改变不成功
        System.out.println(atomicInteger.compareAndSet(2021,1999));//false
        System.out.println(atomicInteger.get()); //1999
    }
}

true

1999

false

1999

UnSafe类

Java是不能调用内存的,c++可以调用内存,navite和uUnSafe类都是java调用c++调用内存的工具

image.png

以下为unsafe中的自增方法 是一个自旋锁


image.png

网络异常,图片无法展示
|

CAS简单总结

比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么久执行,如果不是就一直循环

缺点:

1 由于底层是自旋锁,如果期望值达不到的时候回死循环耗时

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

3 存在ABA问题


  1. CAS的ABA问题(狸猫换太子)

什么是CAS的ABA问题

简单来说,就是两个线程共享一个资源,线程A正常获取,线程B获取之后进行资源改动,但是并未同步告诉给A线程,这时候线程A不知道线程B做了改动,还以为这个资源是原来的资源

类似于乐观锁

package com.wyh.cas;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @program: JUC
 * @description: CAS测试
 * @author: 魏一鹤
 * @createDate: 2022-03-13 20:26
 **/
//什么是CAS? 原子类的一个方法compareAndSet 比较并交换
public class CASDemo {
public static void main(String[] args){
//创建原子类 初始值为2022
        AtomicInteger atomicInteger=new AtomicInteger(2021);
        //===========捣乱的线程=============
        System.out.println(atomicInteger.compareAndSet(2021,2022));//true
        System.out.println(atomicInteger.get()); //1999
        System.out.println(atomicInteger.compareAndSet(2022,2021));
        System.out.println(atomicInteger.get());
//===========期望的线程=============
        System.out.println(atomicInteger.compareAndSet(2021,6666));
        System.out.println(atomicInteger.get());
    }
}

true

2022

true

2021

true

6666

如何解决这种ABA,就是线程故意捣乱的问题呢,使用原子引入

使用原子引入解决CAS ABA问题

带版本号的原子操作 AtomicStampedReference 第一个参数是期望值,第二个参数是版本号,每次操作的时候先获取版本号,这种思想也是乐观锁的思想

public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
package com.wyh.cas;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;
/**
 * @program: JUC
 * @description: CAS测试
 * @author: 魏一鹤
 * @createDate: 2022-03-13 20:26
 **/
//什么是CAS? 原子类的一个方法compareAndSet 比较并交换
public class CASDemo {
public static void main(String[] args){
        //创建原子印用 带版本号的原子操作 第一个参数是期望值,第二个参数是版本号
        //如果泛型是一个包装类,要注意对象的引入问题,在正常业务种 这里面的泛型是一个对象
        AtomicStampedReference<Object> atomicInteger = new AtomicStampedReference<>(1,1);
//模拟两个线程去操作
        //线程A
        new Thread(()->{
//每次操作的时候先获取版本号
            int stamp = atomicInteger.getStamp();
            System.out.println("A1的版本:"+stamp);
//休眠2s保证线程执行顺序
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//CAS设置并替换操作
            System.out.println(atomicInteger.compareAndSet(1, 2, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
            System.out.println("A2的版本:"+atomicInteger.getStamp());
            System.out.println(atomicInteger.compareAndSet(2, 1, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
            System.out.println("A3的版本:"+atomicInteger.getStamp());
        },"A").start();
//线程B
        new Thread(()->{
//每次操作的时候先获取版本号
            int stamp = atomicInteger.getStamp();
            System.out.println("B1的版本:"+stamp);
try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//CAS操作
            System.out.println(atomicInteger.compareAndSet(1, 6, stamp, stamp + 1));
            System.out.println("B2的版本:"+atomicInteger.getStamp());
            },"B").start();
}
目录
相关文章
|
存储 编译器 API
锁与原子操作CAS
锁与原子操作CAS
149 0
|
存储 资源调度 安全
H3C CAS系列 一、CAS初认识
对于虚拟化,可能第一时间大家想到的是虚拟机,而对于虚拟机大家可能第一时间想到的就是我们大多数人都可能比较熟悉的VMware系列产品,比如常用VMware Workstation Pro 、VMware esxi。 而今天我带大家一起认识一款我们国产的虚拟化软件 H3C CAS。
1776 0
|
6月前
|
算法 调度 数据安全/隐私保护
什么是CAS锁
什么是CAS锁
85 0
|
6月前
|
Java API
CAS的超~详细介绍
CAS的超~详细介绍
|
6月前
|
存储 算法 Java
|
6月前
|
算法
原子操作CAS
原子操作CAS
42 0
|
6月前
|
缓存 Linux API
原子操作CAS与锁实现
原子操作CAS与锁实现
|
6月前
|
存储 缓存 算法
理解原子操作与CAS锁
理解原子操作与CAS锁
83 0
|
6月前
|
算法 Java 关系型数据库
CAS
本文主要讲解java中cas的概念及原理
64 0