CAS简介

目录

一.为什么要有CAS

二.什么是CAS机制

三. CAS工作原理

四.CAS的缺点

五.关于CAS中的ABA问题

解决方案


一.为什么要有CAS

我们在多线程安全中有一个经典的双线程++问题

    public static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
                count++;
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
                count++;
            }
        });
        t1.join();
        t2.join();
        t1.start();
        t2.start();
        Thread.sleep(1000);
        System.out.println(count);
    }

就是两个线程同时进行++这个操作,就会导致结果出错

这里结果应该=20000

 我们由此知道了++操作,分为三步,应该加锁确保他的操作是原子性的

//可以将++操作打包到一个枷锁的方法里面   
 synchronized public void func(){
        count++;
    }

但是这样枷锁和解锁,实际上效率并不高效,由此我们引入了一个新的概念

CAS机制

二.什么是CAS机制

简单来说就是进行原子性操作

比如,我们可以将上面的加锁和解锁替换成CAS中的原子操作

所谓CAS的原子操作类,指的是java.util.concurrent.atomic包下,一系列以Atomic开头的包装类。如AtomicBoolean,AtomicUInteger,AtomicLong。

让我们用一用

import java.util.concurrent.atomic.AtomicInteger;

public class demo3 {

//将int count变为AtomicInteger count = new AtomicInteger()
    public static AtomicInteger count = new AtomicInteger();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
//使用原子性的++操作
                count.incrementAndGet();
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
//使用原子性的++操作
                count.incrementAndGet();
            }
        });
        t1.join();
        t2.join();
        t1.start();
        t2.start();
        Thread.sleep(1000);
        System.out.println(count);
    }
}

结果就好了

三. CAS工作原理

我们拿++这个操作来举例

CAS简介_第1张图片

假如我现在有两个线程

线程1和线程2

此时线程1中,有一个数字10开始进行++操作

如果线程2此刻没有进行++操作,也就是说目前只有线程1在进行这个操作的话

就是如下情况

CAS简介_第2张图片

 但是如果,此时线程2也有个++操作,并且比线程1先执行完毕的话

 CAS简介_第3张图片

 所以这样永远能保证++操作的原子性

四.CAS的缺点

1) CPU开销过大

在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很到的压力。

2) 不能保证代码块的原子性

CAS机制所保证的知识一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。

3) ABA问题(重点问题)

这是CAS机制最大的问题所在。

五.关于CAS中的ABA问题

经典ABA例子:取钱问题

假如现在有一位老哥在CAS的取款机上取钱

CAS简介_第4张图片

 这个时候,这个CAS的取款机,在一瞬间开创了线程A和线程B

相当于两个线程在同时进行-操作

如果是这样的话,按照CAS的机制,那么我们理想情况下,应该是这样

CAS简介_第5张图片

但是如果遇到了一种意外情况

线程B遇到了BUG,停止了运行

恰好这个时候,滑稽老哥的妈妈给他汇过去50元

CAS简介_第6张图片

 然后这个时候,BUG修复了,线程B开始运行

CAS简介_第7张图片

 于是我们的滑稽老铁就白白损失了50元

这就是ABA问题

其实B修好了bug之后,不应该以原来的100作为基准

而是应该以线程C没有修改之前的线程A运行的结果作为基准

这里的B是拿C运行的结果作为基准来和原来进行比较,这样肯定是错误的

解决方案

加上版本号

将线程A和B设置为同一版本号,经过比较

如果版本号不同的话,那么我们直接让这个操作失效就好了

你可能感兴趣的:(java学习,java,算法,c++)