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

【JavaEE】CAS

作者主页:paper jie_博客

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

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

其他专栏:《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执行发现预期值和寄存器值一样,但是当前版本号大于读取版本号,操作失败.

相关文章:

【JavaEE】CAS

作者主页:paper jie_博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造&…...

Linux 系统之部署 h5ai 目录列表程序

一、h5ai 介绍 1.1)h5ai 简介 h5ai 是用于 HTTP Web 服务器的现代文件索引器,专注于您的文件。目录以吸引人的方式显示,浏览它们通过不同的视图、面包屑和树概述得到增强。最初 h5ai 是 HTML5 Apache Index 的首字母缩写,但现在它…...

MySQL自增ID耗尽探究:分析与解决方案

MySQL自增ID耗尽探究:分析与解决方案 一、引言 在面试过程中,面试官抛出了一个看似简单却又深入的问题:“MySQL的自增ID用完了,怎么办?” 自增ID耗尽可能看似遥远,但在处理大量数据的系统中,…...

操作系统-操作系统引导(磁盘 操作系统引导过程)

文章目录 总览一个刚买来的磁盘(硬盘)往磁盘安装操作系统后操作系统引导过程例:windows操作系统的初始化程序 总览 一个刚买来的磁盘(硬盘) 此时空空如也 往磁盘安装操作系统后 操作系统在C盘 主引导记录不属于某…...

基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖微信小程序端(十三)

地址簿相关功能 1.1 需求分析和设计1.1.1 产品原型1.1.2 接口设计1.1.3 表设计 1.2 代码实现1.2.1 Mapper层1.2.2 Service层1.2.3 Controller层 1.1 需求分析和设计 1.1.1 产品原型 地址簿,指的是消费者用户的地址信息,用户登录成功后可以维护自己的地…...

SAP S/4HANA 2023 Fully-Activated Appliance 虚拟机版介绍

注:市面上所有在售虚拟机均为拷贝本人所作的虚拟机,存在各种技术问题,请知悉。 SAP S4HANA 2023 FAA版本内置了四个Client: 1、000:SAP初始Client,原则上不能动; 2、100:只激活了US…...

【Docker篇】详细讲解容器相关命令

🎊专栏【Docker】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【如愿】 🎄欢迎并且感谢大家指出小吉的问题🥰 文章目录 🛸容器🌹相关命令🍔案例⭐创建并运…...

LSTM学习笔记

上一篇文章中我们提到,CRNN模型中用于预测特征序列上下文的模块为双向LSTM模块,本篇中就来针对该模块的结构和实现做一些理解。 Bidirectional LSTM模块结构如下图所示: 在Pytorch中,已经集成了LSTM模块,定义如下&…...

Android 13.0 Recent列表不显示某个app

1.概述 在13.0 的系统产品rom定制化开发中,在点击导航栏最近任务列表时,如果做到不显示某个app 呢 一种做法是在app中直接处理 一种做法是在framework中处理 接下来看这两种处理方法 1, app中处理 为该应用AndroidManifest xml文件中主MainActivity设置属性 android:exclu…...

速盾网络:高防ip是什么

速盾网络:高防IP是什么 在当今信息化社会中,网络安全问题日益突出,各种网络攻击威胁层出不穷。为了保护企业的网络安全,提高网络业务的稳定性,高防IP应运而生。那么,什么是高防IP呢? 高防IP是…...

全志A133AndroidQ编译方式

编译uboot: cd longan/brandy/brandy-2.0 ./build.sh -p sun50iw10p1 //A133-android-10-plus\longan\brandy\brandy-2.0\u-boot-2018\u-boot.bin复制为u-boot-sun50iw10p1.bin 或者 //longan\brandy\brandy-2.0\u-boot-2018\configs\sun50iw10p1_defconfig cd …...

2024首更---Web Service 教程

Web Services 简介 Web Services 可使您的应用程序成为 Web 应用程序。 Web Services 通过 Web 进行发布、查找和使用。 您应当具备的基础知识 在继续学习之前,您需要对下面的知识有基本的了解: HTMLXML 如果您希望首先学习这些项目,请在…...

Day29- 贪心算法part03

一、K 次取反后最大化的数组和 题目一:1005. K 次取反后最大化的数组和 1005. K 次取反后最大化的数组和 给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组: 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰…...

RPA与ChatGPT的融合:智能化流程的未来

RPA(Robotic Process Automation)是一种利用软件机器人模拟人类操作的技术,可以实现对各种业务流程的自动化执行。ChatGPT是一种基于深度学习的自然语言生成模型,可以根据给定的上下文生成流畅、连贯、有逻辑的文本。RPA与ChatGPT…...

Ubuntu安装maven并且配置阿里源

ubuntu环境搭建专栏🔗点击跳转 Ubuntu系统环境搭建(十二)——Ubuntu安装maven并且配置阿里源 文章目录 Ubuntu系统环境搭建(十二)——Ubuntu安装maven并且配置阿里源1.安装maven1.1更新源列表1.2安装1.3验证 2.配置阿…...

如何通过idea使用JDK8.0创建Spring项目

目前 IDEA 进行了优化,所以我们在创建 Spring 项目时会发现,以及不能选择通过 JDK8.0 创建了,这是因为官方已经不再提供 JDK8.0 创建 Spring 项目,我们可以通过修改创建 Spring 项目的路径来解决该问题 在创建 Spring 项目的页面&…...

Spark读取kafka(流式和批数据)

spark读取kafka(批数据处理) # 按照偏移量读取kafka数据 from pyspark.sql import SparkSessionss SparkSession.builder.getOrCreate()# spark读取kafka options {# 写kafka配置信息# 指定kafka的连接的broker服务节点信息kafka.bootstrap.servers: n…...

经典目标检测YOLO系列(二)YOLOV2的复现(1)总体网络架构及前向推理过程

经典目标检测YOLO系列(二)YOLOV2的复现(1)总体网络架构及前向推理过程 和之前实现的YOLOv1一样,根据《YOLO目标检测》(ISBN:9787115627094)一书,在不脱离YOLOv2的大部分核心理念的前提下,重构一款较新的YOLOv2检测器,来对YOLOV2有…...

怎样使用崭新的硬盘

新买的一块硬盘,接到电脑上,打开机器,却找不到新的硬盘,怎么回事?新的硬盘是坏的么?怎样才能把新硬盘用起来? 可能有几种原因导致您的电脑无法识别新的硬盘。以下是一些建议的解决方法&#xff…...

Kafka-多线程消费及分区设置

目录 一、Kafka是什么?消息系统:Publish/subscribe(发布/订阅者)模式相关术语 二、初步使用1.yml文件配置2.生产者类3.消费者类4.发送消息 三、减少分区数量1.停止业务服务进程2.停止kafka服务进程3.重新启动kafka服务4.重新启动业…...

MicroOS:Arduino轻量级任务调度内核详解

1. MicroOS:面向Arduino的轻量级任务管理内核概述MicroOS是一个专为Arduino平台设计的极简型实时任务管理器,其核心定位并非替代FreeRTOS或Zephyr等完整RTOS,而是填补Arduino原生loop()单线程模型在多任务调度、精确定时与事件解耦方面的空白…...

从零开始:如何用Python训练一个AI模型(超详细教程)

引言 人工智能(AI)——一个熟悉又神秘的词汇。我们常听说它可以生成诗歌、编写代码、创作艺术,甚至回答各种问题。然而,当你想亲手实现一个“AI 模型”时,却可能感到无从下手。这篇教程正是为你准备的,将带…...

告别调参玄学:手把手教你用‘黎卡提方程’为自动驾驶LQR控制器选择Q和R矩阵

自动驾驶轨迹跟踪实战:从黎卡提方程到LQR调参的工程化思考 当你在仿真环境中第一次看到自己设计的LQR控制器让车辆完美跟踪参考轨迹时,那种成就感难以言喻。但更多时候,我们面对的是震荡的超调曲线、缓慢的收敛速度,以及令人抓狂的…...

OpenClaw 的对话系统是否支持对话流程的可视化编辑?如何定义状态机?

关于OpenClaw对话系统是否支持对话流程的可视化编辑,目前公开的技术文档和社区讨论中并没有明确提及这一功能。从技术实现的角度来看,这类系统通常更侧重于底层对话状态管理和自然语言理解引擎的构建,而非面向产品经理或非技术人员的可视化编…...

LeifHomieLib:ESP32/8266轻量级Homie v3 MQTT设备库

1. LeifHomieLib 项目概述LeifHomieLib 是一个专为 ESP8266 和 ESP32 平台设计的轻量级 Homie v3 协议实现库,其核心目标是为资源受限的物联网边缘节点提供符合 Homie 规范的 MQTT 设备抽象能力。该库并非 Homie v3 标准的全功能实现,而是聚焦于与 openH…...

Logisim音乐盒背后的数字电路:计数器、ROM与蜂鸣器如何奏出《终生误》

Logisim音乐盒背后的数字电路:计数器、ROM与蜂鸣器如何奏出《终生误》 当一段熟悉的旋律从蜂鸣器中流淌而出,很少有人会思考这背后隐藏的数字魔法。本文将带您拆解一个基于Logisim的音乐盒设计,揭示计数器如何像指挥家一样协调时序、ROM怎样扮…...

硬核盘点|2026年好用AI论文写作工具榜单,毕业论文免费写还合规

2026 年实测 10 款主流 AI 论文工具,千笔AI以全流程覆盖 语义级降重 免费查重领跑综合榜;ThouPen 稳坐留学生毕业全流程工具头把交椅;免费工具中DeepSeek Scholar、豆包学术版表现亮眼,30 分钟即可生成万字高质量初稿&#xff0…...

从SWF中提取供应链安全控制:JPEXS Free Flash Decompiler安全研究

从SWF中提取供应链安全控制:JPEXS Free Flash Decompiler安全研究 【免费下载链接】jpexs-decompiler JPEXS Free Flash Decompiler 项目地址: https://gitcode.com/gh_mirrors/jp/jpexs-decompiler JPEXS Free Flash Decompiler是一款强大的开源工具&#x…...

从AlexNet到MobileNet:深度可分离卷积如何用1/4参数量实现高效推理?

从AlexNet到MobileNet:深度可分离卷积如何用1/4参数量实现高效推理? 在移动互联网时代,AI模型部署正经历从云端到边缘的范式转移。当我们谈论"高效推理"时,实际上是在探讨一个核心矛盾:如何在有限的硬件资源…...

lite-avatar形象库入门:如何查找、预览并下载心仪的数字人形象

lite-avatar形象库入门:如何查找、预览并下载心仪的数字人形象 1. 数字人形象库简介 在数字人项目开发中,一个合适的虚拟形象往往能让用户体验大幅提升。lite-avatar形象库正是为解决这一需求而生的专业资源库。 这个基于HumanAIGC-Engineering/LiteA…...