当前位置: 首页 > news >正文

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

8e19eee2be5648b78d93fbff2488137b.png

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

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

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

目录

一:CAS指令

1:概念

2:伪代码例子说明

3:优点

二:原子类

1:引入

2:代码示例

3:与volatile的区别

4:标准库源码

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

四:CAS中ABA问题

1:引入

2:极端情况

3:解决方案


一:CAS指令

1:概念

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

2:伪代码例子说明

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

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

1c8c72bca32d460da5b549d1d5b66cc7.png

3:优点

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

二:原子类

1:引入

在Java中:

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

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

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

java.util.concurrent.atomic

46690935fa5740c0a57ea8c8e57d7b08.png

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

 d95117553dff4069b86164e440df43fc.png

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

(1)方法总结

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

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

3:与volatile的区别

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

4:标准库源码

f24e028c87a44c8783646915f83b4cbb.png

17844d4d3272428cb32eb6207dfee80d.png

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

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

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

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

b394bf9f41d14493abcb5009969fb1a6.png

b2918816e1e04b348c32129bfc243214.png

 

四:CAS中ABA问题

1:引入

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

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

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

2:极端情况

存钱fadb290b30264d36b31b76e4aef8c259.png

3:解决方案

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

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


http://www.mrgr.cn/news/39708.html

相关文章:

  • 基于Java+VUE+echarts大数据智能道路交通信息统计分析管理系统
  • PyQt5整合爬虫制作图片爬取器-幽络源
  • ansible学习之 Facts
  • PC流量转移动流量,提升网盘拉新收益
  • Study Plan For Algorithms - Part44
  • 在起草行业标准时,如何确保格式统一?
  • 网站建设方案书怎么写
  • VUE前后端分离毕业设计题目项目有哪些,VUE程序开发常见毕业论文设计推荐
  • 银河麒麟服务器:更新软件源
  • 如何查看NVIDIA Container Toolkit是否配置成功
  • Python中的Threading模块:让并发编程变得轻松
  • 数据转换新利器,开启企业高效之路
  • WebSocket 2024/9/30
  • 如何使用WinRAR锁定压缩文件,防止文件被修改或删除?
  • 详解Java之继承与多态
  • 为别人做嫁衣——代理模式
  • 101条团队管理秘籍
  • 算法-数组笔记
  • 诗画紫砂壶
  • 跨颜色人员重识别