JUC并发编程_深入理解CAS

JUC并发编程_深入理解CAS

      • CAS 的基本原理
      • CAS 的优缺点
      • Java 中的 CAS 实现
      • 原子引用 AtomicStampedReference 解决 ABA 问题


CAS 的基本原理

CAS 属于乐观锁的一种实现方式

比较(Compare):检查内存位置的值是否等于预期原值。
执行(Swap):如果相等,则将该位置值更新为新值。
原子性:上述两个步骤作为一个整体是原子的,不可中断。


CAS 的优缺点

优点:

  • 非阻塞算法:CAS是一种非阻塞算法,它不会造成线程挂起或阻塞,因此不会引起线程上下文切换,从而减少了系统的开销。

  • 高并发:在多线程环境下,CAS能有效避免使用锁(Locks)带来的问题,如死锁、线程饥饿等,从而提高了系统的并发性能。

缺点:

  • ABA问题:如果某个线程将内存位置的值从A改为B,然后又改回A,此时另一个线程使用CAS进行检查时会认为该值没有变化,但实际上它已经变化过了。

  • 循环时间长开销大:如果CAS操作一直不成功,那么它会一直进行重试,这会增加CPU的开销。

  • 只能保证一个共享变量的原子操作:CAS操作只能保证单个共享变量的原子操作,对于多个共享变量,CAS无法保证其原子性。


Java 中的 CAS 实现

在Java中,CAS主要通过 java.util.concurrent.atomic 包下的类来实现,如 AtomicIntegerAtomicLongAtomicReference 等。这些类提供了 compareAndSet 方法,该方法就是 CAS 操作的 Java 实现。

例如,AtomicInteger 的 compareAndSet 方法签名如下:

public final boolean compareAndSet(int expect, int update)

该方法会尝试将当前值设置为 update,但条件是当前值等于 expect。如果当前值等于 expect,则成功更新并返回 true;否则不更新并返回 false。

import java.util.concurrent.atomic.AtomicInteger;
public class CASDemo {
	// CAS compareAndSwap: 比较并交换
	public static void main(String[] args) {
		AtomicInteger atomicInteger = new AtomicInteger(2020);
		// public final boolean compareAndSet(int expect, int update)
		// 如果是期望的值就更新,否则不更新
		System.out.println(atomicInteger.compareAndSet(2020, 2021));
		System.out.println(atomicInteger.get());
		// 通过自旋锁进行自增
		atomicInteger.getAndIncrement()
		System.out.println(atomicInteger.compareAndSet(2020, 2021));
		System.out.println(atomicInteger.get());
	}
}

getAndIncrement 方法的底层是通过 自旋锁 的方式实现的(循环时间长开销大)

public final int getAndIncrement() {
	return unsafe.getAndAddInt(this, valueOffset, 1);
}

public final int getAndAddInt(Object var1, long var2, int var4) {
	int var5;
	do {
		var5 = this.getIntVolatile(var1, var2);
	} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
		return var5;
    }
}

原子引用 AtomicStampedReference 解决 ABA 问题

解决ABA问题的一种常见且有效的方法是使用带有版本号或时间戳的原子操作,这样可以确保在比较并交换(CAS)操作时,不仅能检查值是否相等,还能检查该值自上次读取以来是否未被其他线程修改过。

在 Java 中,java.util.concurrent.atomic 包提供了 AtomicStampedReference 类,它正是为了解决ABA问题而设计的,它在设置值的时候,除了要校验预期原值,还要校验版本号是否变更。

public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp)
import java.util.concurrent.atomic.AtomicStampedReference;  

public class ABASolution {  
    public static void main(String[] args) {
    	// 使用AtomicStampedReference 定义共享变量(初始值1,版本号0)
        AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(1, 0);  
        
        // 尝试将值从1更新为2  
        int[] expectedStamp = {ref.getStamp()};  
        int expectedValue = ref.getReference();  
        boolean resultA = ref.compareAndSet(expectedValue, 2, expectedStamp[0], expectedStamp[0] + 1);  

        // 尝试将值从1(但实际上是2,因为已经更新了)更新回1  
        // 这里预期原值和实际值不一致,预期原版本号也与实际版本号不一致,返回失败。
        boolean resultB1 = ref.compareAndSet(1, 1, expectedStamp[0], expectedStamp[0] + 1); 

        // 正确操作:应重新获取最新的版本号  
        int currentStamp = ref.getStamp();  
        boolean resultB2 = ref.compareAndSet(2, 1, currentStamp, currentStamp + 1);
    }  
}

上述代码需要注意对象引用问题:

  • Integer 使用了对象缓存机制,默认范围为 -128 ~ 127,只有超出这个范围的值才会创建新对象。
  • compareAndSet 比较的是对象是否相同而不是值是否相同。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【中间件——基于消息中间件的分布式系统的架构】

1. 基于消息中间件的分布式系统的架构 从上图中可以看出来&#xff0c;消息中间件的是 1&#xff1a;利用可靠的消息传递机制进行系统和系统直接的通讯 2&#xff1a;通过提供消息传递和消息的排队机制&#xff0c;它可以在分布式系统环境下扩展进程间的通讯。 1.1 消息中间件…

影视站群程序大对比,苹果cmsv10 vs海洋cms

在影视站群程序领域&#xff0c;苹果CMSv10和海洋CMS是两款备受站长们青睐的程序。它们分别具备各自的优势&#xff0c;适合不同需求的站群管理和优化。以下是两者的详细对比&#xff0c;并重点介绍苹果CMS的主要优势和插件功能。 苹果CMSv10简介 maccmscn 苹果CMSv10&#x…

CV之OCR:GOT-OCR2.0的简介、安装和使用方法、案例应用之详细攻略

CV之OCR&#xff1a;GOT-OCR2.0的简介、安装和使用方法、案例应用之详细攻略 目录 GOT-OCR2.0的简介 1、更新 GOT-OCR2.0的安装和使用方法 1、安装 安装环境cuda11.8torch2.0.1 安装包 安装Flash-Attention GOT权重&#xff1a;1.43G 2、演示 3、训练 4、评估 GOT-…

记录Mac编译Android源码踩过的坑

学习Android源码&#xff0c;如果电脑配置还不错&#xff0c;最好还是下载一套源码&#xff0c;经过编译后导入到Android Studio中来学习&#xff0c;这样会更加的直观&#xff0c;代码之间的跳转查看会更加方便。因此&#xff0c;笔者决定下载并编译一套源码&#xff0c;以利于…

[Redis][哨兵][下]详细讲解

目录 1.安装部署(基于Docker)1.编排Redis主从节点2.编排Redis-Sentinel节点 2.重新选举1.redis-master宕机之后2.redis-master重启之后3.总结 3.选举原理4.总结 1.安装部署(基于Docker) 1.编排Redis主从节点 编写docker-compose.yml 创建/root/redis/docker-compose.yml&…

【web安全】——信息收集

一、收集域名信息 1.1域名注册信息 工具&#xff1a;站长之家 whois查询 SEO综合查询 1.2子域名收集 原理&#xff1a;字典爆破&#xff0c;通过字典中的各种字符串与主域名拼接&#xff0c;尝试访问。 站长之家 直接查询子域名 ip138.com https://phpinfo.me/domain/ …

StoryMaker 在文本到图像的生成过程中实现一致的字符

StoryMaker 是一种个性化解决方案&#xff0c;它不仅能保持多个角色场景中面部的一致性&#xff0c;还能保持服装、发型和身体的一致性&#xff0c;从而有可能制作出由一系列图像组成的故事。 StoryMaker 生成图像的可视化。 前三行讲述的是 "上班族 "一天的生活&…

创建javaWeb项目(详细版本)2021年2月

1、新建一个java项目 2、点击工程名称&#xff0c;找到add framework support&#xff0c;并点击 建好如图 3、分别在工程目录下创建resourse文件夹和web目录下创建classes和lib文件夹 建好如图 4、file找到 project structure 5、选中resourse 将其mark as sources 6、路径改…

关于frp Web界面-----frp Server Dashboard 和 frp Client Admin UI

Web 界面 官方文档&#xff1a;https://gofrp.org/zh-cn/docs/features/common/ui/ 目前 frpc 和 frps 分别内置了相应的 Web 界面方便用户使用。 客户端 Admin UI 服务端 Dashboard 服务端 Dashboard 服务端 Dashboard 使用户可以通过浏览器查看 frp 的状态以及代理统计信…

godot4.2入门项目 dodge_the_creep学习记录

前言 在学习博客Godot4 你的第一个2d游戏中的项目时&#xff0c;遇到了点小问题&#xff0c;记录一下。 官方项目 传送门 问题 怪兽直接从屏幕中间部分冒出来&#xff0c;以及角色出现时位于屏幕外角色被设置的背景图遮挡 解决方法 1.节点的位置没有对齐&#xff0c;正确示例…

Apache APISIX学习(2):安装Grafana、prometheus

一、Grafana安装 1、介绍 Grafana 是一个监控仪表系统&#xff0c;它是由 Grafana Labs 公司开源的的一个系统监测 (System Monitoring) 工具。它可以大大帮助你简化监控的复杂度&#xff0c;你只需要提供你需要监控的数据&#xff0c;它就可以帮你生成各种可视化仪表。同时它…

Vue-Bag-Admin 采用漂亮的 Naive UI 构建的开源中后台系统,基于 Vue3 / Vite / TypeScript 等最新的前端技术栈

这是一款完成度很高、实用性很强的 admin 前端框架&#xff0c;颜值不错&#xff0c;推荐给大家。 Vue-Bag-Admin 在官网上也直接称为 Bag-Admin&#xff0c;这是一款专门为企业项目搭建中后台管理平台的前端框架&#xff0c;基于目前最新的前端技术栈 Vue3、Vite、TypeScript…

程序设计题(65—72)

第六十五题 题目 请编写函数fun&#xff0c;它的功能是&#xff1a;计算下列级数和&#xff0c;和值由函数值返回。 例如&#xff0c;当n10&#xff0c;x0.3时&#xff0c;函数值为1.349859。 #include <conio.h> #include <stdio.h> #include <math.h> #…

5.使用 VSCode 过程中的英语积累 - Go 菜单(每一次重点积累 5 个单词)

前言 学习可以不局限于传统的书籍和课堂&#xff0c;各种生活的元素也都可以做为我们的学习对象&#xff0c;本文将利用 VSCode 页面上的各种英文元素来做英语的积累&#xff0c;如此做有 3 大利 这些软件在我们工作中是时时刻刻接触的&#xff0c;借此做英语积累再合适不过&a…

react:React Hook函数

使用规则 只能在组件中或者其他自定义的Hook函数中调用 只能在组件的顶层调用&#xff0c;不能嵌套在if、for、 其他函数中 基础Hook 函数 useState useState是一个hook函数&#xff0c;它允许我们向组件中添加一个状态变量&#xff0c;从而控制影响组件的渲染结果 示例1…

人生苦短,我用Python✌

面向代码的解释型语言 数据开发和AI 编程语言:让计算机了解我们干什么&#xff0c;翻译官 1.下载软件 解释器安装 点击第二个 改路径 D:\python 安装 测试 winr打开 输入代码 输出 退出环境 exit&#xff08;&#xff09; 新建文本文档后缀改成py 编写 运行 安装编写代码…

开放词汇全景分割

开放词汇全景分割是一种先进的计算机视觉任务&#xff0c;它旨在将图像中的每个像素分割并分类到预先定义或未定义的类别中。这与传统的图像分割不同&#xff0c;后者通常仅限于识别有限的、预先定义的对象类别。开放词汇全景分割的目标是识别和处理图像中的任何可能的对象&…

Fastadmin 前台任意文件读取漏洞

漏洞描述 FastAdmin是一个基于ThinkPHP5和Bootstrap的后台开发框架&#xff0c;支持权限管理、响应式开发、多语言、模块化开发、CRUD和自由可扩展等功能。 漏洞复现 FOFA body"fastadmin.net" || body"<h1>fastadmin</h1>" && tit…

SpringMVC源码-SpringMVC框架中Spring父容器和SpringMVC子容器加载的流程以及SpringMVC九大内置组件的初始

一、Spring父容器启动 SpringMVC 的项目结构如下: applicationContext.xml spring的配置文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.o…

微调大模型(Finetuning Large Language Models)—Evaluation(六)

1. 微调后对模型进行评估 模型的评估目前没有统一的标准&#xff0c;有从正向角度&#xff0c;核对是否命中&#xff0c;当然也有从反向角度&#xff0c;考虑未命中的错误分析。 常见的评估方式如图所示&#xff1a; 本节学习资料地址&#xff1a;传送门 2. 代码测试 2.1 …