【JavaEE】——CAS指令和ABA问题

简介: CAS指令,伪代码,原子类,CAS中ABA问题,CAS底层分析

  image.gif 编辑

阿华代码,不是逆风,就是我疯

你们的点赞收藏是我前进最大的动力!!

希望本文内容能够帮助到你!!

目录

一:CAS指令

1:概念

2:伪代码例子说明

3:优点

二:原子类

1:引入

2:代码示例

3:与volatile的区别

4:标准库源码

三:CAS是如何避免线程安全问题

四:CAS中ABA问题

1:引入

2:极端情况

3:解决方案


一:CAS指令

1:概念

CAS是CPU中的一条特殊的指令,它的功能就是完成“比较和交换”

2:伪代码例子说明

伪代码:只能表示一种逻辑,并不能实现编译执行

注:CAS指令一般只关注内存当中的值,寄存器当中的值是多少不打紧,用完就不要了

image.gif 编辑

3:优点

CAS指令不涉及锁,也能保证线程的安全

二:原子类

1:引入

在Java中:

先是操作系统对指令封装成api

然后JVM在对api进行封装,把CAS的api放到了unsafe这个包里(注:这个包里指令会涉及一些系统底层的内容,使用的话是风险操作)

Java标准库中,对CAS再进一步封装,提供了一些工具类,其中最主要的一个工具叫“原子类”

java.util.concurrent.atomic

image.gif 编辑

2:代码示例

我们还是沿用【JavaEE】——线程的安全问题和解决方式_java线程安全 线程不安全-CSDN博客

这篇文章中,用两个线程去自增到10000计数器这个例子

前面我们是通过synchronized加锁方式解决,这里我们使用原子类进行代码编译

package thread;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-09-29
 * Time: 14:15
 */
public class ThreadDemon36 {
   // private static int result = 0;
    //括号里的参数就是result的初始值
    private static AtomicInteger result = new AtomicInteger(0);
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
           for(int i = 1 ; i <= 5000 ; i++){
               result.getAndIncrement();//自增相当于result++
               //result++;
           }
        });
        Thread t2 = new Thread(() -> {
            for(int i = 1 ; i <= 5000 ; i++){
                result.getAndIncrement();//自增
                //result++;
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(result.get());//获取到result中持有的值
    }
}

image.gif

image.gif 编辑

这里的++操作,不在是(load,add,save)三条指令了,而是打包成了CAS指令,成为一个天然的原子性指令,这样就避免了,多线程中两者的指令相互穿插执行,也就避免了线程安全问题

(1)方法总结

①.getAndIncrement()——相当于count++

②.incrementAndGet()——相当于++count

3:与volatile的区别

volatile是禁止指令重排序(因为操作非原子性嘛),

4:标准库源码

image.gif 编辑

image.gif 编辑

三:CAS是如何避免线程安全问题

核心点:就是通过CAS和while循环的搭配,来确保内存中的值和寄存器当中的值是一样的,

这里的代价就是“自旋”——while循环嘛,但是一般循环不了几次就OK了,这点资源损耗可以忽略

不计,CAS还是很香的~~~

image.gif 编辑

image.gif 编辑

image.gif 编辑

四:CAS中ABA问题

1:引入

上述图文看明白之后,我们可以总结出一点,CAS判断内存和寄存器中的值是否相等,本质上就是在判断——是否有其他线程穿插指令

想象一下,在CAS之前,如果有一个线程穿插进去把数值修改了,紧接着第二个线程也穿插进去把错误的数值又修改回来了,那么CAS是感知不到有线程穿插进来的(如穿~~)

一般来说这也不会引起什么bug之类的

2:极端情况

存钱 image.gif 编辑

3:解决方案

(1)约定数据变化本身就是单向的,只能增加或者只能减少

(2)对于本身必须就是双向变化的数据,引入一个版本号——这个版本号就是只能增加不能减少

相关文章
|
7月前
|
算法 Java
浅谈一下CAS和ABA问题
浅谈一下CAS和ABA问题
79 0
|
2月前
|
安全
【多线程】CAS、ABA问题详解
【多线程】CAS、ABA问题详解
33 0
|
4月前
|
Java
JUC(10)深入理解CAS和ABA
这篇文章深入探讨了Java中的CAS(Compare-And-Swap,比较并交换)操作,解释了CAS的工作原理、应用场景以及存在的循环耗时、单变量原子性保证和ABA问题等缺点,并介绍了如何使用原子引用和版本号来解决ABA问题。
JUC(10)深入理解CAS和ABA
|
7月前
|
Java
18.AtomicReference、AtomicStampReference底层原理。多个变量更新怎么保证原子性?CAS的ABA问题怎么解决?
18.AtomicReference、AtomicStampReference底层原理。多个变量更新怎么保证原子性?CAS的ABA问题怎么解决?
64 0
18.AtomicReference、AtomicStampReference底层原理。多个变量更新怎么保证原子性?CAS的ABA问题怎么解决?
|
7月前
详解CAS及ABA问题
详解CAS及ABA问题
117 0
解决CAS机制中ABA问题的AtomicStampedReference详解
AtomicStampedReference是一个带有时间戳的对象引用,能很好的解决CAS机制中的ABA问题,这篇文章将通过案例对其介绍分析。
315 0
解决CAS机制中ABA问题的AtomicStampedReference详解
什么是 CAS? CAS 有哪些缺点?ABA 问题是什么?
什么是 CAS? CAS 有哪些缺点?ABA 问题是什么?
212 0
|
安全 Java 测试技术
Java面试题之CAS和ABA问题
原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不能被打乱,也不可以被切割而只执行其中的一部分(不可中断性)。将整个操作视为一个整体,资源在该次操作中保持一致,这是原子性的核心特征。
Java面试题之CAS和ABA问题
JAVA中CAS-ABA的问题解决方案AtomicStampedReference
JAVA中CAS-ABA的问题解决方案AtomicStampedReference
125 0
|
安全 Java
AtomicStampedReference是怎样解决CAS的ABA问题
但凡对Java有一点深入就会知道 CAS,即 compareAndSwap。在Java中使用 Unsafe 类提供的native方法可以直接操作内存,其中就有对compareAndSwap的实现。
209 0
AtomicStampedReference是怎样解决CAS的ABA问题