前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CAS,你看不懂的,我教你

CAS,你看不懂的,我教你

原创
作者头像
Joseph_青椒
发布2023-08-26 20:58:18
1720
发布2023-08-26 20:58:18
举报
文章被收录于专栏:java_josephjava_joseph

引入

CAS重要就不多说了,好多文章,都讲的不是很全面,通过我自己的理解,来帮助大家!

什么是CAS

用在并发,是一种思想,一种算法,也是cpu的指令,cpmpare and swap

核心思想是,认为一个值是A,是的话,我就改成B,不是的话,证明被改过了,我就不改了

主要是三个操作:

内存值V 预期值A 要修改的值B

比如两个cpu修改一个内存值,先到的CPU,通过比较,发现没改过,就直接改了,后到的,一看,改过了,那么他就不改了

实质:是一个cpu指令,cpu保障了它的原子性,不会出现线程安全问题

CAS的等价语义

代码语言:javascript
复制
/**
 * 模拟CAS操作,等价代码
 */
public class SimulatedCAS {
?
    private volatile int value;
?
    /**
     * cpu中,这个方法是一条指令
     * @param expectedValue
     * @param newValue
     * @return
     */
    public synchronized int compareAndSwap(int expectedValue,int newValue){
        int oldValue = value;
        if(oldValue==expectedValue){
            value = newValue;
        }
        return oldValue;
    }
?
}

案例演示

两个线程竞争,一个失败

代码语言:javascript
复制
/**
 * 模拟CAS操作,等价代码
 */
public class TwoThreadCompetition implements Runnable{
?
    private volatile int value;
?
    /**
     * cpu中,这个方法是一条指令
     * @param expectedValue
     * @param newValue
     * @return
     */
    public synchronized int compareAndSwap(int expectedValue,int newValue){
        int oldValue = value;
        if(oldValue==expectedValue){
            value = newValue;
        }
        return oldValue;
    }
?
    public static void main(String[] args) throws InterruptedException {
        TwoThreadCompetition r = new TwoThreadCompetition();
        r.value=0;
        Thread t1 = new Thread(r,"线程a");
        Thread t2 = new Thread(r,"线程b");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
?
    @Override
    public void run() {
        int i = compareAndSwap(0, 1);
        if(i==0){
            System.out.print("线程:"+Thread.currentThread().getName());
            System.out.println("这一次修改成功了,原来的值是:"+i);
        }
        try {
            Thread.sleep(111);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(i==1){
            System.out.print("线程:"+Thread.currentThread().getName());
            System.out.println("这一次修改失败了,原理的值是:"+i);
        }
?
    }
}

应用场景

乐观锁,利用CAS,比如数据库,通过版本号,进行库存扣减,乐观锁

并发容器、

原子类、

原子类如何通过Java代码如何实现CAS的?

比如AtmoicInteger,会加载一个Unsafe工具,直接操作内存数据

通过volatile保存可见性

比如getAndAdd方法,调用的getAndAddInt方法

image-20230826203426077
image-20230826203426077

通过do while实现乐观锁

Unsafe类,java无法直接访问底层操作系统容,而是通过本地native方法访问,,jdk提供了一个类Unsafe

提供了硬件级别的原子操作

利用Unsafe类,操作底层,主要是compareAndSwapInt方法,拿到变量在内存中的地址

通过Atomic::compxchg实现原子性的比较和替换,完成cas的过程

缺点

ABA问题,

5才可以修改,但是修改了一次,又被其他线程修改为5了

比如,修改,修改了两次,我认为的时候,就是跟没修改过一样,可以通过加个版本号,来避免ABA问题

自旋时间长,消耗CPU

比如原子类中的操作,通过dowhile和Unsafe的compareAndswapInt方法,自旋完成乐观锁,消耗CPU

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引入
  • 什么是CAS
  • 案例演示
  • 应用场景
    • 原子类如何通过Java代码如何实现CAS的?
    • 缺点
      • ABA问题,
        • 自旋时间长,消耗CPU
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
        http://www.vxiaotou.com