1 Star 0 Fork 0

heyifan/MarkDownNote

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
CAS.md 4.39 KB
一键复制 编辑 原始数据 按行查看 历史
yifan.he 提交于 2021-03-04 16:19 . first

什么是CAS

CAS 全称是CompareAndSwap即__比较替换__的意思,是__原子操作__,采用__乐观锁__的概念,底层对应着CPU的__cmpxchg__指令,核心参数就是当前值A,要修改的值B,内存值V三个参数,在高并发的场景下不断循环比较当前值和内存值,一样就修改,否则就重试或者放弃更新。

为什么要使用CAS

与Syncronized和Lock相比而言,CAS是不需要在资源上加锁的,多个线程都可以直接去修改共享资源,但只能被一个线程修改。Syncronized和Lock都是只有一个线程去操作共享资源。在一定的场景下,CAS比较高效,比如一个数的累加,底层使用CAS的AutomaticInteger类就可以实现线程安全的自增。

CAS会产生的问题

ABA的问题:有三个线程,共享资源a为100,一号线程将a准备改为50,此时cpu被线程2抢占,修改为50,2号线程修改完后CPU被3号线程抢占,修改为100,修改后1号线程继续执行,此时1号线程不知道a已经有一次修改了,但依然能修改成功,a这就是ABA的问题。

ABA解决方法

版本号:a值每次被修改时版本号都会加1,此时线程1在比较时额外加上版本号的比较,就可以解决ABA的问题,可以使用A

版本号工具类:

  • AtomicStampedReference:带时间版本戳的原子操作类,可以控制ABA问题,保证到修改几次。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
 
/**
 * @ClassName ReferenceTest
 * @Description 多个变量需要同时Atomic控制时,封装到一个对象类中 AtomicReference解决。一个对象更新成另一个对象
 **/
public class ReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        MiddleStatus status=new MiddleStatus(10,5);
        AtomicReference<MiddleStatus> ato=new AtomicReference<>(status);
 
        MiddleStatus expect=new MiddleStatus(12,6);
        MiddleStatus newStatus=new MiddleStatus(20,10);
        //保证原子操作,更新之前会比较 expect
        ato.compareAndSet(expect,newStatus);
        System.out.println("status = " + ato.get()); //更新失败,MiddleStatus{esfCount=10, zfCount=5}
 
        ato.compareAndSet(status,newStatus);
        System.out.println("status = " + ato.get());//更新成功,MiddleStatus{esfCount=20, zfCount=10}
    }
    private static class MiddleStatus{
        private int esfCount;
        private int zfCount;
 
        public MiddleStatus(int esf,int zf){
            this.esfCount=esf;
            this.zfCount=zf;
        }
        @Override
        public String toString() {
            return "MiddleStatus{" +
                    "esfCount=" + esfCount +
                    ", zfCount=" + zfCount +
                    '}';
        }
    }
}
  • AtomicMarkableReference:可以控制ABA问题,保证是否修改过。
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;
 
/**
 * @ClassName StampTest
 * @Description 通过时间戳控制原子操作,保证是否有修改,并制定修改了多少次
 **/
public class StampTest {
    private static class  StampStatus{
        public int sCount;
        public StampStatus(int c){
            this.sCount=c;
        }
    }
 
    public static void main(String[] args) {
        StampStatus s1=new StampStatus(2);
        //通过Val和初始时间戳创建StampReference
        int initialStap=2;
        //AtomicStampedReference 可通过Stamp知道已经修改几次
        AtomicStampedReference<StampStatus> ato=new AtomicStampedReference<>(s1,initialStap);
        ato.compareAndSet(new StampStatus(3),new StampStatus(6),3,ato.getStamp()+1);
        System.out.println(ato.getReference().sCount);//期望值和期望引用不正确,更新失败
 
        //AtomicMarkableReference 可通过Mark知道是否更新过
        AtomicMarkableReference<StampStatus> ato2=new AtomicMarkableReference<>(s1,false);
        ato2.compareAndSet(new StampStatus(3),new StampStatus(6),false,true);
        System.out.println(ato2.isMarked());
        System.out.println(ato2.getReference().sCount);//期望标志和期望引用不对,修改失败
    }
}	
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Java
1
https://gitee.com/hyf216/mark-down-note.git
git@gitee.com:hyf216/mark-down-note.git
hyf216
mark-down-note
MarkDownNote
master

搜索帮助

Cb406eda 1850385 E526c682 1850385