欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java CAS算法简介及简单模拟CAS算法

程序员文章站 2022-04-03 15:56:53
CAS算法的流程是:先读取一个预期值(**A**) →从内存中读取一个值(**V**),如果A == V,那么就将新的值(**B**)给写入内存,如果A != V,那就不做任何操作。...


CAS(Compare-And-Swap:比较并替换)

CAS是英文单词CompareAndSwap的缩写,意思就是:比较并替换。简单来说就是比较之后再看情况是否需要替换。CAS是乐观锁思想的一种实现方式。


一、CAS运算流程

CAS算法的流程是:先读取一个预期值(A) → 从内存中读取一个值(V),如果A == V,那么就将新的值(B)给写入内存,如果A != V,那就不做任何操作。

二、CAS的优缺点

优点:①可以避免优先级倒置和死锁。②允许更高程度的并行机制

缺点:①ABA问题:(可能会造成数据丢失
比如有三个线程ThreadA、ThreadB、ThreadC,这三个线程都要操作一个值value(value初始值为100)。
三个线程的目的:
ThreadA(value = 100 → value = 50);
ThreadB(value = 100 → value = 50);
ThreadC(value = 50 → value = 100);
刚开始线程A和B都开始运行,两个线程读取到的预期值都是100,此时线程A将100给改为50,之后C线程突然出现,将50给改成了100,然后线程B被插队了就很不爽,准备去修改值,但是读取到了内存值是100 == 预期值100,于是就把100给修改成了50。可是线程B很纳闷,前两个线程到底搞什么飞机,咋啥也没干,他们是没操作成功还是根本没修改这个值?这内存中的值还是100,我还以为我会修改失败呢。
所以,线程B纳闷的点就是CAS的缺点,它只能去判断内存值和预期值是否相等来得出这个数是否被别人修改过,但是却不知道,读取了预期值100之后,中间被插了无数队,轮到我去修改时,发现内存值等于预期值就以为前面的线程都没有修改这个数,然后线程B就把值给修改了。然而线程B修改值却一直以为他操作的数是被插队之前的那个数,所以线程B的修改会忽略掉中间插队那些线程的操作,所以线程B的修改可能会造成数据丢失。
解决办法:Java提供了一个带有标记的原子类AtomicStampedReference,它可以通过控制变量值的版本来保证CAS的正确性

②CAS只能保证一个共享变量的原子性操作。
解决办法:可以把多个变量放进一个对象里来进行CAS操作

③循环时间长,CPU的开销大。

三、模拟CAS算法(只是模拟,并非Java底层的真正实现)

/**
 * @author 弹弹霹雳
 * @create 2020-11-22-11:43
 */
//模拟CAS算法
public class TestCompareAndSwap {
    public static void main(String[] args) {
        CompareAndSwap cas = new CompareAndSwap();
        //创建10个线程
        for(int i = 0 ; i < 10; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                	//获取预期值
                    int expectedValue = cas.getValue();
                    //尝试去修改值,并接收修改情况
                    boolean flag = cas.compareAndSet(expectedValue, (int)(Math.random() * 101));
                    System.out.println(flag);
                }
            }).start();
        }
    }
}

class CompareAndSwap{
	//通过volatile保证内存的可见性
    private volatile int value = 0;

    public int getValue(){
        return this.value;
    }
	
    public synchronized int compareAndSwap(int expectedValue, int newValue){
    	//读取内存中的值
        int oldValue = this.value;
        //如果内存中的值和预期值相等,那么我们就修改内存中的值
        if(expectedValue == oldValue){
            this.value = newValue;
        }
        //返回内存值,如果value被修改,返回的是修改前的值,主要用来给compareAndSet判断是否修改成功
        return oldValue;
    }

    public boolean compareAndSet(int expectedValue, int newValue){
    	//如果预期值和内存值相等,就返回true否则返回false
        return expectedValue == compareAndSwap(expectedValue, newValue);
    }
}

本文地址:https://blog.csdn.net/weixin_48029654/article/details/109951707