【JavaEE】CAS

作者主页:paper jie_博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将MySQL基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《MySQL》《C语言》《javaSE》《数据结构》等

内容分享:本期将会分享CAS知识.

目录

什么是CAS

CAS怎么实现的

CAS的应用

实现原子类

实现自旋锁

CAS的ABA问题

什么是ABA问题

ABA带来的问题

解决方法


什么是CAS

CAS称为compare and swap,就是比较和交换的意思,它涉及到的操作就是(内存中的原数据为C, 旧的预期值为A, 需要修改的新值为B.):

1. 比较 A 与 C的值是不是一样

2. 如果相等,就会将B的值写入A中

3.返回操作是否成功.

CAS本质上就是一条指令.用来进行比较和交换,而指令本身就具有原子性.基于CAS就给实现线程安全有了一条新的选择. 之前为了线程安全需要加锁,而加锁就可能会造成堵塞.但CAS本身就具有原子性,就不需要加锁,不加锁也就不会造成堵塞.合理的使用CAS也可以解决线程安全的问题.

CAS怎么实现的

简答来说就是:

Java层面的CAS利用的就是unsafe这个类提供的CAS操作.

unsafe的CAS依赖的是JVM针对与不同操作系统实现的Atomic::cmpxchg

Atomic::cmpxchg的实现是使用了汇编的CAS操作,且使用CPU硬件提供的lock机制保证其原子性.

反正就是因为硬件提供了支持,软件层面才能做到.

CAS的应用

实现原子类

标准库中就提供了Java.cutil.concurrent.atomic 包,里面的类都是基于这种方式来实现的. 典型就是Atomiclnteger类,其中的方法getAndIncrement就是相当于i++.

AtomicInteger atomicInteger = new AtomicInteger(0);
// 相当于 i++
atomicInteger.getAndIncrement();

伪代码:

class AtomicInteger {private int value;public int getAndIncrement() {int oldValue = value;while ( CAS(value, oldValue, oldValue+1) != true) {oldValue = value;}return oldValue;
}

假设两个线程都调用到了这个方法.

1.两个线程都读到了value值到oldvalue中.

2. 线程1先执行CAS操作. 因为value和oldvalue一样,就会直接对value赋值.

3其后线程2再执行CAS操作就会发现value和oldvalue不同就会再次将value的值给oldvalue进入循环

4接下来第二次执行CAS,就发现value和oldvalue一样,就会发生赋值.

通过类似于这种方式就可以实现一个原子类.不需要重量级锁也可以高效的完成多线程的自增操作.(这里其实在代码角度不是原子的,但是在硬件上可以让一条指令完成这个操作,也就变成原子的了)

通过这样的代码就可以实现一个原子类.它是不需要使用重量级锁的,这样可以高效的完成多线程的自增操作.

实现自旋锁

我们基于CAS可以实现更加灵活的锁,获取到更多的控制权.

自旋锁伪代码:

这里核心就是使用CAS,当owner不为null时,它就会一直循环判断,当owner为null时,它就会操作成功,将这个线程的地址赋值给owner,结束了可以调用构造方法来将owner置为null,相当于解锁.

public class SpinLock {private Thread owner = null;public void lock(){// 通过 CAS 看当前锁是否被某个线程持有. // 如果这个锁已经被别的线程持有, 那么就⾃旋等待. // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程. while(!CAS(this.owner, null, Thread.currentThread())){}}public void unlock (){this.owner = null;}}

CAS的ABA问题

什么是ABA问题

我们知道CAS的核心就是比较和交换,判断预期值和内存值是不是一样再交换.但是会有一种情况:

假设有两个线程t1和t2,都需要对一个共享变量num100来进行减50操作. 他们需要进行的步骤:

1. 读取num的值到寄存器中

2.比较看相不相同,相同就修改成50

这时当t1执行到第二步操作时,t2插队进来将这个减50操作完成了,这时num变成了50,后面又有一个t3线程插到t1线程前面,将num的值加50,这时num变成了100.终于轮到t1执行第二步操作时,它发现这个num为100,和寄存器中的值一样,它就会进行-50操作.

这就是ABA现象.

ABA带来的问题

粗略来看,这样是没有什么影响的.但是再一些极端情况下就会产生一些不好的影响. 比如:

小帅今天打算去银行取50块钱.它对ATM机点了一下,发现没反应,就又点了一下.这时ATM机就会产生t1和t2两个相同的-50的线程. 当t1执行到第二步后,t2插队进来执行,将100变成了50.等到t1再执行的时候,它又被插队了,这时小帅的女朋友给它的账户中存了50块钱,账户余额就变成了100.终于等到t1执行时它会发现账户里的值和寄存器中的值一样,于是它的减50操作就成功了.

这就会发生小帅的50块钱不翼而飞的现象.

解决方法

我们可以给需要修改的值引入一个版本号.在比较当前值和预期值时,也要比较版本号相不相同.

1. CAS操作在读取内存值的时候,也需要读取版本号.

2. 在进行比较值的时候,也要比较当前版本号和读取版本号相不相同.相同而修改数据,版本号+1.如果当前版本号大于读取的版本号就表示操作失败了.

举个栗子:
比如小帅取钱.取款机都创建了两个线程,都是执行-50的操作. t1获取到了存款为100,版本号为1.t2获取到了存款为100,版本号为1.

t2扣款成功,存款为50,版本号更新为2.

小帅的女朋友给小帅存了50,存款为100,版本号更新为3.

最终t1执行发现预期值和寄存器值一样,但是当前版本号大于读取版本号,操作失败.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/627351.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

μ综合设计控制器

μ综合设计控制器是一种基于μ分析的控制器设计方法,用于提高控制器的鲁棒性和性能。μ分析是一种数学工具,用于描述和比较控制系统在不同参数变化下的性能。通过μ综合设计,可以综合运用各种控制策略,以达到更好的控制效果。 μ…

【双指针】001移动零_C++

题目链接:移动零 目录 题目解析 代码书写 知识补充 题目解析 题目让我们求必须在不复制数组的情况下,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 这题我们可以用双指针的方法来写: 我们这里将用两个数组下标来…

条码WMS仓储管理系统的价值与优势

在全球化和数字化的时代,企业面临着诸多挑战。在复杂的运营环境中,如何提高运营效率和效果,降低成本,增强竞争力,成为企业关注的焦点。而库存管理作为企业运营的关键环节,其重要性不言而喻。本文将深入探讨…

北交所交易手续费标准?哪家证券公司开通北交所券商交易手续费佣金万2?

北交所(Beijing Exchange)是指位于中国北京的一家金融交易所。北交所是中国政府为推动金融改革和国际化市场而设立的交易场所。它提供包括股票、债券、期货、外汇等多种金融产品的交易服务。北交所的目标是促进中国金融市场的发展,吸引国内外…

golang文件相对路径问题

目录结构 2.具体代码: const dataFile "../data/data.json"_, fileName, _, _ : runtime.Caller(1)dataPath : path.Join(path.Dir(fileName), dataFile)fmt.Println(dataPath)// open filefile, err : os.Open(dataPath)if err ! nil {log.Fatalln(err…

在IntelliJ IDEA中集成SSM项目

SSM项目:springMVC为控制器、spring 为事务层、 MyBatis 负责持久 首先看下集成后项目结构: 1、打开IntelliJ IDEA,点击 "File" -> "New" -> "Project"。 点击Finish,此时我们就已经创建了一…

postman自动化接口测试

背景描述 有一个项目要使用postman进行接口测试,接口所需参数有: appid: 应用标识;sign:请求签名,需要使用HMACSHA1加密算法计算,签名串是:{appid}${url}${stamp};stamp&#xff1…

Idea如何重置免费使用30天

大家都知道,Idea的使用,不是免费的。需要自己购买,获取证书才能使用,那么怎么无限试用30天呢!首次,自己点击 点击Evaluate按钮,就可以免费使用。 过了30天的试用期。重新试用30天。我们需要如下…

6-keto-PGF1α ELISA kit—ENZO LIFE SCIENCE

高灵敏ELISA试剂盒,3小时内可检测低至1.40 pg/ml 6-酮前列腺素F1α 6-酮-前列环素F1α(6-keto-PGF1α)是前列环素(PGI2)的稳定水解产物。由于前列环素在缓冲液中的半衰期很短(2-3分钟)&#xff…

vue2使用electron以及打包配置

1.创建项目 vue create vue-project 2.安装electron vue add electron-builder会自动安装相关依赖 安装成功后会在src下自动生成一个background.js文件就是相应的electron的配置信息 use strictimport { app, protocol, BrowserWindow } from electron import { createProto…

重启阿里云ESC服务器后,数据库与jar包外面无法访问bug

bug 重启了服务器,发现从外面无法连接数据库 原因 使用firewall-cmd --list-all命令查看服务器防火墙的配置,发现没有开启3306端口的开放,虽然我们在安全组设置3306端口但是防火墙没有开启,外面是依然无法访问的。 firewall-cm…

Python网络爬虫进阶:自动切换HTTP代理IP的应用

前言 当你决定做一个网络爬虫的时候,就意味着你要面对一个很大的挑战——IP池和中间件。这两个东西听起来很大上,但其实就是为了让你的爬虫不被封杀了。下面我就来给你讲讲如何搞定这些东西。 第一步:创建爬虫IP池的详细过程 首先&#xf…

ACM:每日学习 状压dp

状压dp: 状压dp是对一般dp的改进: //对于判断多种物品的取法,开多维数组比较麻烦,也不好开,使用二进制来表示物品的取与否。 //使用二进制的话,位运算就更能省时间了,而且更会节省空空间&…

[LitCTF 2023]easy_shark

解压缩,发现需要输入密码,使用010打开,发现frflags和deflags都被修改了,这就会造成压缩包伪加密 把他们都改为0,再打开 将流量包使用wirshark打开 过滤http,并追踪 得到以下信息 看到了一个类似于flag格…

文章阅读总结:多传感器融合:GNSS微弱信号场景的补救措施

[TOC](多传感器融合导航论文积累) # 知识点总结 ## 因子图 Factor Graph 是概率图的一种,是对函数因子分解的表示图,一般内含两种节点,变量节点和函数节点。 因子图存在着:**两类节点: 变量节点和对应的函数节点**变量…

4 - JdbcTemplate

spring 框架如何处理对数据库的操作呢? 1. 基本介绍 文档:JdbcTemplate APIs : /spring-framework-5.3.8/docs/javadoc-api/index.html JdbcTemplate 是 Spring 提供的访问数据库的技术。可以将 JDBC 的常用操作封装为模板方法 已经提供了特别多的 API 2. 使用…

Linux网络文件共享服务之FTP协议

目录 一、存储类型 1、直连式存储(DAS) 2、存储区域网络(SAN) 3、网络附加存储(NAS) 二、 FTP文件传输协议 1、FTP协议的工作原理 1.1 FTP协议的工作流程 1.2 FTP协议的两种工作模式 1.2.1 主动模…

flutter报错Cannot hit test a render box that has never been laid out

出现这个问题的原因可能是因为你把一个ListView或者GridView放到了一个没有设置大小的容器里面导致的,所以意思是不能渲染那一个没有布局过的容器。我这里遇到的错误是因为我把GridView放到了一个Container里面,并且我没有设置Container宽高。 就导致了那…

嵌入式工作岗位未来会不会越来越少?

今日话题,嵌入式工作岗位未来会不会越来越少?未来的嵌入式岗位机会将会逐渐增多,因为嵌入式技术是万物互联的基础,从智能手表到智能汽车,嵌入式都扮演着关键角色。虽然相比计算机科学CS,嵌入式领域的天花板…

中间件框架知识进阶

概述 近期从不同渠道了解到了一些中间件相关的新的知识,记录一下收获。涉及到的中间件包括RPC调用、动态配置中心、MQ、缓存、数据库、限流等,通过对比加深理解,方便实际应用时候更明确如何进行设计和技术选型。 一、RPC框架中间件系列 1、…