Java CAS是什么,它的底层原理?

news2025/1/6 13:18:37

文章目录

  • 前言
  • 一、CAS是什么
  • 二、CAS底层原理
    • 1、UnSafe类(Native方法)
    • 2、CAS思想(自旋锁)
    • 3、为什么使用CAS,不用synchronized?
    • 4、CAS缺点
    • 5、ABA问题,原子引用更新?

前言

对于CAS部分学习,予以记录!

一、CAS是什么

CAS全称为Compare-And-Swap比较并交换,它是一条CPU并发原语。

CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现出汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。

原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。

二、CAS底层原理

CAS底层原理是通过 Unsafe类(Native方法) + CAS思想(自旋锁) 实现的

1、UnSafe类(Native方法)

UnSafe类是CAS的核心类,由于Java方法无法直接访问底层系统,则需要通过本地(native)方法来访问,Unsafe相当于一个后门,基于该类可以直接操作特定内存的数据。

Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为Java中CAS操作的执行依赖于Unsafe类的方法。

Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都是直接调用操作系统底层资源执行相应任务

查看Unsafe类路径:
JDK8:\jdk8u381\jre\lib\rt.jar\sun\misc\Unsafe.class
JDK17:\jdk17008\lib\src.zip\jdk.unsupported\sun\misc\Unsafe.java

变量VALUE表示该变量值在内存中的偏移地址,因为Unsafe就是根据当前对象与其内存偏移地址获取数据的

在这里插入图片描述

2、CAS思想(自旋锁)

public static void main(String[] args) {
    AtomicInteger atomicInteger = new AtomicInteger(5);
    System.out.println(atomicInteger);
	// 它的功能是判断内存某个位置的值是否为预期值,如果是则返回true且将其更改为新的值,这个过程是原子的。
    System.out.println(atomicInteger.compareAndSet(5, 2019));
    System.out.println(atomicInteger.compareAndSet(2019, 6));
	// 自增并返回当前的atomicInteger值
    atomicInteger.getAndIncrement();
}

在这里插入图片描述

类似i++,对AtomicInteger.getAndIncrement()进行源码分析:

变量value用volatile修饰,保证了多线程之间的内存可见性

在这里插入图片描述

实际调用Unsafe类中的getAndAddInt()方法

在这里插入图片描述

进入Unsafe类,getIntVolavtile()通过o与offset获取在主内存中的值,weakCompareAndSetInt()比较并交换
该对象当前的值与v比较(自旋锁):
如果相同,说明在此期间其他线程没有更新这个值,更新该对象当前值为v + delta,并返回true,
如果不同,说明在此期间其他线程更新了这个值,继续从主内存中取值再比较,直到更新完成。

在这里插入图片描述

o当前对象,offset该对象值的引用地址,expected通过o与offset找出的主内存中真实的值,x变动后的值

在这里插入图片描述

在这里插入图片描述

底层汇编语言:

在这里插入图片描述

小总结:

CAS( CompareAndSwap):比较当前工作内存中的值和主内存中的值,如果相同则执行规定操作否则继续比较直到主内存和工作内存中的值一致为止。

CAS应用:CAS有3个操作数,内存值V,旧的预期值A,要修改的更新值B当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做

3、为什么使用CAS,不用synchronized?

CAS:保证了一致性,又兼顾了并发性
synchronized:只保证了一致性

4、CAS缺点

循环时间长开销很大

只能保证一个共享变量的原子操作

引出ABA问题

5、ABA问题,原子引用更新?

AtomicInteger:CAS --> Unsafe --> CAS底层原理 --> ABA问题 --> 原子引用更新 --> 如何规避ABA问题

CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差中会导致数据的变化

比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且线程two进行了一些操作将值变成了B,然后线程two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后线程one操作成功。

尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的

原子引用,AtomicReference <T>

解决方案:带版本号(时间戳)的原子引用, AtomicStampedReference<T>

public static void testAtomicReference() {
     AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(100, 1);

     System.out.println("=======以下是ABA问题的产生与解决=========");
     new Thread(() -> {
         int stamp = atomicStampedReference.getStamp();
         System.out.println(Thread.currentThread().getName() + "\t当前值:" + atomicStampedReference.getReference()
                 + "\t第1次版本号:" + stamp);
         // 暂停1s t3线程,保证t4线程取到与t3相同的版本号
         try {
             TimeUnit.SECONDS.sleep(1);
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }

         atomicStampedReference.compareAndSet(100, 101,
                 atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
         System.out.println(Thread.currentThread().getName() + "\t当前值:" + atomicStampedReference.getReference()
                 + "\t第2次版本号:" + atomicStampedReference.getStamp());

         atomicStampedReference.compareAndSet(101, 100,
                 atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
         System.out.println(Thread.currentThread().getName() + "\t当前值:" + atomicStampedReference.getReference()
                 + "\t第3次版本号:" + atomicStampedReference.getStamp());

     }, "t3").start();

     new Thread(() -> {
         int stamp = atomicStampedReference.getStamp();
         System.out.println(Thread.currentThread().getName() + "\t当前值:" + atomicStampedReference.getReference()
                 + "\t第1次版本号:" + stamp);
         // 暂停3s t4线程,保证t3线程完成一次ABA操作
         try {
             TimeUnit.SECONDS.sleep(3);
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }

         boolean res = atomicStampedReference.compareAndSet(100, 2023,
                 stamp, stamp + 1);
         System.out.println(Thread.currentThread().getName() + "\t修改成功否:" + res);
         System.out.println(Thread.currentThread().getName() + "\t当前实际最新值:"
                 + atomicStampedReference.getReference() + "\t当前实际最新版本号:"
                 + atomicStampedReference.getStamp());
     }, "t4").start();
}

在这里插入图片描述

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

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

相关文章

SSD入门到精通系列-总目录

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《SSD入门到精通系列》 综述&#xff1a; SSD-序 [SSD综述1.1] 导论 免责声明&#xff1a; 本文根据公开信息整理&#xff0c;旨在介绍更多的存储知识&#xff0c;所载文章仅为作者观点&#xff0c;不构成投…

lv9 嵌入式开发 数据库sqlite

1 数据库基本概念 数据&#xff08;Data&#xff09; 能够输入计算机并能被计算机程序识别和处理的信息集合 数据库 &#xff08;Database&#xff09; 数据库是在数据库管理系统管理和控制之下&#xff0c;存放在存储介质上的数据集合 2 常用的数据库 大型数据库…

竞赛 深度学习猫狗分类 - python opencv cnn

文章目录 0 前言1 课题背景2 使用CNN进行猫狗分类3 数据集处理4 神经网络的编写5 Tensorflow计算图的构建6 模型的训练和测试7 预测效果8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习猫狗分类 ** 该项目较为新颖&a…

google scholar 显示异常流量

有时候可能会出现下图警告&#xff0c;导致打不开谷歌学术的界面&#xff0c;我们需要修改一下访问网址 在网站后面添加 .pk 或者 .pr &#xff0c;如下&#xff1a; https://scholar.google.com.pk/https://scholar.google.com.pr/

网络变压器/网络滤波器/脉冲变压器接地电路的选择

Hqst华强盛(盈盛)电子导读&#xff1a;网络变压器/网络滤波器/脉冲变压器&#xff0c;以下都称网络变压器&#xff0c;它的接地在网络布置中非常重要&#xff0c;它可以有效地提高信号的稳定性和可靠性。 网络变压器接地的布置方式通常有以下几种&#xff1a; 一&#xff0c;单…

Rust学习日记(二)变量的使用--结合--温度换算/斐波那契数列--实例

前言&#xff1a; 这是一个系列的学习笔记&#xff0c;会将笔者学习Rust语言的心得记录。 当然&#xff0c;这并非是流水账似的记录&#xff0c;而是结合实际程序项目的记录&#xff0c;如果你也对Rust感兴趣&#xff0c;那么我们可以一起交流探讨&#xff0c;使用Rust来构建程…

《算法通关村—原来如此简单》

《算法通关村—原来如此简单》 理解层序遍历 我们有一个二叉树&#xff0c;我们如何去进行一层一层的遍历呢&#xff1f; 需要我们借用一个数据结构来进行遍历&#xff0c;数据结构就是队列。我们首先把根节点放入队列中&#xff0c;然后从此进行遍历。如何进行遍历&#xf…

SpringBoot项目从resources目录读取文件

SpringBoot 从 resources 读取文件 使用 Spring 给我们提供的工具类来进行读取 File file org.springframework.util.ResourceUtils.getFile("classpath:人物模板.docx");可能读取失败&#xff0c;出现如下错误&#xff1a; java.io.FileNotFoundException: clas…

JSP 中医知识管理系统myeclipse开发sql数据库BS模式java编程网页结构

一、源码特点 JSP 中医知识管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;比较流行的ssh框架系统具有完整的源代码和数据库&#xff0c;myeclipse开发系统主要采用B/S模式开发。 javaWeb中医知识系统 二、功能介绍 此次系统主要…

电脑提示由于找不到msvcp120.dll无法继续执行代码的问题如何解决

在打开软件过程中&#xff0c;我们可能会遇到各种错误和问题。其中之一就是msvcp120.dll无法继续执行代码的问题。这个问题通常是由于缺少或损坏的Microsoft Visual C Redistributable Packages导致的。为了解决这个问题&#xff0c;我们可以采取以下四个解决方案&#xff1a; …

【逗老师的无线电】BI1FQO教你整骚活,纯4G MMDVM热点版

开篇图&#xff0c;看我手搓出来的尺寸超小的MMDVM热点盒子&#xff08;都不能叫做盒子啦&#xff09; 咱就说这玩意尺寸有多小&#xff0c;架构有多简单&#xff0c;4G网卡直连双工热点版&#xff0c;省去树莓派或者OpenWrt&#xff0c;功耗低至0.几W。开机秒快。 基本原…

大数据管理平台是什么?如何利用工单系统提升企业管理效率?

随着数字化时代的来临&#xff0c;大数据管理平台已成为企业优化运营、提高竞争力的关键工具。工单管理系统作为大数据管理平台的核心组件&#xff0c;对于企业服务的优化和提升发挥着至关重要的作用。本文小编将为您揭示工单管理系统在大数据管理平台中的重要地位&#xff0c;…

libpcap之数据分流

当前系统都是多核系统&#xff0c;为了充分利用多核优势&#xff0c;数据包可以在底层就进行分流&#xff0c;可以通过多线程/多进程对同一个接口的数据进行并行的处理。 一、实验 一个server/client程序一个简单的抓包程序&#xff0c;抓取server/client之间的通信数据 1.1 …

Bat批量处理

一&#xff1a;创建文件夹 excel创建文件 复制出来新建文本文件 另存为bat 双击bat 二&#xff1a;批量移动文件 A列&#xff1a;获取的文件名列表 dir /b/o:n> original.txt B列&#xff1a;填充序号 C列公式&#xff1a;每隔9行增加1 INT((ROW(B1)-1)/9)1 D列公式&am…

CDN与WAF防火墙:强强联手,守护您的网站安全

随着互联网的普及&#xff0c;网站安全问题变得愈发重要。恶意攻击、数据泄露和服务中断等问题都可能给网站和用户带来严重损害。在保护网站免受这些威胁的过程中&#xff0c;内容分发网络&#xff08;CDN&#xff09;和Web应用程序防火墙&#xff08;WAF&#xff09;是两个强大…

C++算法 —— 贪心(2)

文章目录 1、柠檬水找零2、将数组和减半的最少操作次数3、最大数4、摆动序列5、最长递增子序列6、递增的三元子序列7、最长连续递增子序列 1、柠檬水找零 860. 柠檬水找零 如果一开始顾客给了10块&#xff0c;那就直接结束。给了5块那就收下。之后每一个位置&#xff0c;都需要…

进阶C语言-指针的进阶(三)

模拟实现qsort函数 &#x1f388;1.测试bubble_sort&#xff0c;排序整型数组&#x1f388;2测试bubble_sort&#xff0c;排序结构体数组 &#x1f4dd;关于qsort函数&#xff0c;我们可以先去cpluplus网站上面了解一下&#xff1a; //1.排序整型数组&#xff0c;两个整型可以…

Linux 上的轻量级浏览器

导读大多数 Linux 桌面环境中包含的基本图像查看器可能不足以满足你的需要。如果你想要一些更多的功能&#xff0c;但仍然希望它是轻量级的&#xff0c;那么看看这四个 Linux 桌面中的图像查看器&#xff0c;如果还不能满足你的需要&#xff0c;还有额外的选择。 当你需要的不…

竞赛选题 深度学习实现语义分割算法系统 - 机器视觉

文章目录 1 前言2 概念介绍2.1 什么是图像语义分割 3 条件随机场的深度学习模型3\. 1 多尺度特征融合 4 语义分割开发过程4.1 建立4.2 下载CamVid数据集4.3 加载CamVid图像4.4 加载CamVid像素标签图像 5 PyTorch 实现语义分割5.1 数据集准备5.2 训练基准模型5.3 损失函数5.4 归…

整理的一些Java细节问题

1. 为什么要有无参构造&#xff1f; 在 Java 中&#xff0c;如果一个类没有显式定义构造方法&#xff0c;编译器会自动生成一个默认的无参构造方法&#xff08;也称为默认构造方法&#xff09;。无参构造方法是一个没有任何参数的构造方法。 无参构造方法的存在有几个重要原因…