深入理解CAS

2024-05-21 16:26:36 浏览数 (2)

深入理解CAS (Compare and swap )

CAS:比较当前工作内存中的值和主内存中的值,如果这个值是期望的,就执行操作,否则就一直循环。

举例对比

不使用CAS,多线程环境不使用原子类保证线程安全i (基本数据类型),加同步锁 synchronized

代码语言:javascript复制
public class T1 {
    volatile int number=0;
    //读取
    public int getNumber(){
        return number;
    }
    //写入加锁保证原子性
    public synchronized  void setNumber(){
        number  ;
    }
}

使用CAS,在多线程环境利用原子类 AtomicInteger 保证线程安全i (基本数据类型),类似乐观锁

代码语言:javascript复制
import java.util.concurrent.atomic.AtomicInteger;
 
public class T1 {
    AtomicInteger atomicInteger=new AtomicInteger();
    //读取
    public int getAtomicInteger(){
        return atomicInteger.get();
    }
    //写入原子整型类保证原子性
    public void setAtomicInteger(){
        atomicInteger.incrementAndGet();
    }
}

缺点

ABA

问题描述:线程t1将它的值从A变为B,再从B变为A。同时有线程t2要将值从A变为C。但CAS检查的时候会发现没有改变,但是实质上它已经发生了改变 。可能会造成数据的缺失。

解决方法:CAS还是类似于乐观锁,同数据乐观锁的方式给它加一个版本号或者时间戳,如AtomicStampedReference。

自旋消耗资源

问题描述:多个线程争夺同一个资源时,如果自旋一直不成功,将会一直占用CPU。

解决方法:破坏掉while死循环,当超过一定时间或者一定次数时,return退出。JDK8新增的LongAddr和ConcurrentHashMap类似的方法。当多个线程竞争时,将粒度变小,将一个变量拆分为多个变量,达到多个线程访问多个资源的效果,最后再调用sum把它合起来。虽然base和cells都是volatile修饰的,但感觉这个sum操作没有加锁,可能sum的结果不是那么精确。

多变量共享一致性问题

解决方法: CAS操作是针对一个变量的,如果对多个变量操作,

  1. 可以加锁来解决。
  2. 封装成对象类解决。

0 人点赞