【Java】CAS锁

news/2024/11/23 3:20:38/

一、什么是CAS机制(compare and swap)

1.概述

CAS的全称为Compare-And-Swap,直译就是对比交换。是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值。经过调查发现,其实现方式是基于硬件平台的汇编指令,就是说CAS是靠硬件实现的,JVM只是封装了汇编调用,那些AtomicInteger类便是使用了这些封装后的接口。

简单解释:CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先比较下在旧值有没有发生变化,如果没有发生变化,才交换成新值,发生了变化则不交换。

2.CAS算法的作用:

解决多线程条件下使用锁造成性能损耗问题的算法,保证了原子性,这个原子操作是由CPU来完成的

3.CAS的原理:

CAS算法有三个操作数,通过内存中的值(V)、预期原始值(A)、修改后的新值(B)。

(1)如果内存中的值和预期原始值相等, 就将修改后的新值保存到内存中。

(2)如果内存中的值和预期原始值不相等,说明共享数据已经被修改,放弃已经所做的操作,然后重新执行刚才的操作,直到重试成功。

在这里插入图片描述

注意
(1)预期原始值(A)是从偏移位置读取到三级缓存中让CPU处理的值,修改后的新值是预期原始值经CPU处理暂时存储在CPU的三级缓存中的值,而内存指定偏移位置中的原始值。

(2)比较从指定偏移位置读取到缓存的值与指定内存偏移位置的值是否相等,如果相等则修改指定内存偏移位置的值,这个操作是操作系统底层汇编的一个原子指令实现的,保证了原子性。

  • JVM中CAS是通过UnSafe类来调用操作系统底层的CAS指令实现。
  • CAS基于乐观锁思想来设计的,其不会引发阻塞,synchronize会导致阻塞。
import java.util.concurrent.atomic.AtomicInteger;public class CASDemo {public static void main(String[] args) {AtomicInteger atomicInteger = new AtomicInteger(2023);//期望时5,如果是5则改成2022System.out.println(atomicInteger.compareAndSet(2023, 2022) + "\t" + atomicInteger.get());System.out.println(atomicInteger.compareAndSet(2023, 2022) + "\t" + atomicInteger.get());}
}

结果

true	2022
false	2022

二、CAS和syncronized的比较

  • CAS线程不会阻塞,线程一致自旋
  • syncronized会阻塞线程,会进行线程的上下文切换,会由用户态切换到内核态,切换前需要保存用户态的上下文,而内核态恢复到用户态,又需要恢复保存的上下文,非常消耗资源。

三、CAS的缺点

(1)ABA问题

如果一个线程t1正修改共享变量的值A,但还没修改,此时另一个线程t2获取到CPU时间片,将共享变量的值A修改为B,然后又修改为A,此时线程t1检查发现共享变量的值没有发生变化,但是实际上却变化了。

解决办法

使用版本号,在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么A-B-A 就会变成1A-2B-3A。从Java1.5开始JUC包里提供了一个类AtomicStampedReference来解决ABA问题。AtomicStampedReference类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前版本号是否等于预期版本号,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

(2)CAS频繁失败导致CPU开销大

循环时间长开销会比较大:自旋重试时间,会给CPU带来非常大的执行开销

(3)只能支持一个变量的原子操作,不能保证整个代码块的原子操作

只能保证一个共享变量的原子操作,不能保证同时对多个变量的原子性操作

解决办法

从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作

四、CAS使用注意事项

(1)CAS需要和volatile配合使用

CAS只能保证变量的原子性,不能保证变量的内存可见性。CAS获取共享变量的值时,需要和volatile配合使用,来保证共享变量的可见性

(2)CAS适用于并发量不高、多核CPU的情况

CPU多核情况下可以同时执行,如果不合适就失败。而并发量过高,会导致自旋重试耗费大量的CPU资源


http://www.ppmy.cn/news/27970.html

相关文章

【CSS】CSS 层叠样式表 ① ( 简介 | CSS 引入方式 - 内联样式 | 内联样式语法 | 内联样式缺点 )

文章目录一、CSS 层叠样式表二、CSS 引入方式 - 内联样式1、内联样式语法2、内联样式缺点3、内联样式代码示例① 核心代码示例② 完整代码示例③ 执行结果一、CSS 层叠样式表 CSS 全称 Cascading Style Sheets , 层叠样式表 ; 作用如下 : 设置 HTML 页面 文本内容 的 字体 , 颜…

学了一年Java的我,想转嵌入式了

秋名山码民的主页 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 🙏作者水平有限,如发现错误,还请私信或者评论区留言! 目录前言为啥我想去转行?如果我现在选择转硬件,我…

《英雄编程体验课》第 12 课 | 递归

文章目录 零、写在前面一、搜索算法的原理二、深度优先搜索三、基于DFS的记忆化搜索四、基于DFS的剪枝五、基于DFS的A*(迭代加深,IDA*)零、写在前面 该章节节选自 《夜深人静写算法》,主要讲解最基础的搜索算法,其中用到的思想就是递归,当然,如果已经对本套体验课了如指…

【一天一门编程语言】Lisp 语言程序设计极简教程

Lisp 语言程序设计极简教程 Lisp 是一种古老的编程语言,它的特点是拥有很高的表示能力和灵活的可扩展性,拥有大量的现成函数库,同时也是一种动态类型的语言,十分适合用来实现大规模软件系统。本文介绍了 Lisp 程序设计的基本知识,帮助读者快速上手。 一、Lisp 简介 Lis…

完美的vue3动态渲染菜单路由全程

前言: 首先,我们需要知道,动态路由菜单并非一开始就写好的,而是用户登录之后获取的路由菜单再进行渲染,从而可以起到资源节约何最大程度的保护系统的安全性。 需要配合后端,如果后端的值不匹配&#xff0…

读懂分布式事务

一、概述 1.1 什么是分布式事务 事务我们都很熟悉,事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成这组操作的各个单元,要么全部成功,要么全部失败。 事务有四大特性: Atomic&#xf…

FSM(有限状态机)

FSM有限状态机FSM创建控制有限状态机的脚本设置FSM状态机下的各个状态添加测试类FSM的优点FSM 虽然Unity已经有了动画状态机,但是为了代码的开放封闭原则,这时FSM有限状态机的作用就凸显了出来。 创建控制有限状态机的脚本 先创建一个脚本用来控制有限…

西北工业大学大学物理(I)下2019-2020选填考题解析

单选题12个,24分。1量子数考查前三个量子数由薛定谔方程决定,最后一个关于自旋的由狄拉克方程决定由这些量子数可以给出原子的壳层结构。考试其实考的不深,记住这个表就够了。2 书上18、19章量子物理的著名实验:光电效应&#xff…