带你完整复习CAS 和 ABA 问题

Posted 南淮北安

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带你完整复习CAS 和 ABA 问题相关的知识,希望对你有一定的参考价值。

文章目录

一、CAS的概念:比较并交换

CAS(Compare And Swap)指比较并交换。CAS算法CAS(V, E, N)包含3个参数,V表示内存里的值,E表示传入的值,N表示新值。

在且仅在V值等于 E值时,才会将V值设为 N,如果 V值和 E值不同,则说明已经有其他线程做了更新,当前线程什么都不做。

最后,CAS返回当前V的真实值。

二、CAS的特性:乐观锁

CAS操作采用了乐观锁的思想,总是认为自己可以成功完成操作。

在有多个线程同时使用CAS操作一个变量时,只有一个会胜出并成功更新,其余均会失败。失败的线程不会被挂起,仅被告知失败,并且允许再次尝试,当然,也允许失败的线程放弃操作

基于这样的原理,CAS操作即使没有锁,也可以发现其他线程对当前线程的干扰,并进行恰当的处理。

三、CAS自旋等待

在JDK的原子包java.util.concurrent.atomic里面提供了一组原子类,这些原子类的基本特性就是在多线程环境下,在有多个线程同时执行这些类的实例包含的方法时,会有排他性。

其内部便是基于CAS算法实现的,即在某个线程进入方法中执行其中的指令时,不会被其他线程打断;而别的线程就像自旋锁一样,一直等到该方法执行完成才由JVM从等待的队列中选择另一个线程进入。

相对于synchronized阻塞算法,CAS是非阻塞算法的一种常见实现。

由于CPU的切换比CPU指令集的操作更加耗时,所以CAS的自旋操作在性能上有了很大的提升。JDK具体的实现源码如下:


在以上代码中,getAndIncrement采用了CAS操作,每次都从内存中读取数据然后将此数据和加1后的结果进行CAS操作,如果成功,则返回结果,否则重试直到成功为止。

四、ABA问题

对CAS算法的实现有一个重要的前提:需要取出内存中某时刻的数据,然后在下一时刻进行比较、替换,在这个时间差内可能数据已经发生了变化,导致产生ABA问题

ABA问题指第1个线程从内存的V位置取出A,

这时第2个线程也从内存中取出A,并将V位置的数据首先修改为B,接着又将V位置的数据修改为A,这时第1个线程在进行CAS操作时会发现在内存中仍然是A,然后第1个线程操作成功。

尽管从第1个线程的角度来说,CAS操作是成功的,但在该过程中其实V位置的数据发生了变化,只是第1个线程没有感知到罢了,这在某些应用场景下可能出现过程数据不一致的问题。

部分乐观锁是通过版本号(version)来解决ABA问题的,具体的操作是乐观锁每次在执行数据的修改操作时都会带上一个版本号,在预期的版本号和数据的版本号一致时就可以执行修改操作,并对版本号执行加1操作,否则执行失败

因为每次操作的版本号都会随之增加,所以不会出现ABA问题,因为版本号只会增加,不会减少。

以上是关于带你完整复习CAS 和 ABA 问题的主要内容,如果未能解决你的问题,请参考以下文章

CAS缺点

高并发面试必问:CAS 引起ABA问题解决方案

CAS 和 ABA 问题

juc学习三(CAS中ABA问题产生和解决)

Java CAS 和 ABA问题

CAS 的ABA 问题