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

举报
三三是该溜子 发表于 2025/05/05 10:46:58 2025/05/05
【摘要】 ​目录一:CAS指令二:原子类三:CAS是如何避免线程安全问题四:CAS中ABA问题一:CAS指令1:概念CAS是CPU中的一条特殊的指令,它的功能就是完成“比较和交换”2:伪代码例子说明伪代码:只能表示一种逻辑,并不能实现编译执行注:CAS指令一般只关注内存当中的值,寄存器当中的值是多少不打紧,用完就不要了3:优点CAS指令不涉及锁,也能保证线程的安全二:原子类1:引入在Java中:先是操...

目录

一:CAS指令

二:原子类

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

四:CAS中ABA问题

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

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

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

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

二:原子类
1:引入
在Java中:

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

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

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

java.util.concurrent.atomic

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中持有的值
    

    }
    }

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

(1)方法总结

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

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

3:与volatile的区别
volatile是禁止指令重排序(因为操作非原子性嘛),

4:标准库源码

三:CAS是如何避免线程安全问题
核心点:就是通过CAS和while循环的搭配,来确保内存中的值和寄存器当中的值是一样的,

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

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

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

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

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

2:极端情况
存钱

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

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

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。