CAS理解和说明

2024-09-05 00:52
文章标签 理解 说明 cas

本文主要是介绍CAS理解和说明,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1.CAS是什么?

2.CAS的应用场景

2.1 实现原子类

2.2 实现自旋锁

3.CAS的典型问题:ABA问题 


1.CAS是什么?

CAS:全称compare and swap(比较并交换)

我们假设内存中的原始数据V,旧的预期值A,需要修改的新值B

1.比较A与V是否相等(比较)

2.如果比较相等,将B写入V(交换)

3.返回操作是否成功

 在这里最特别的是,上述这个CAS的过程,并非是通过一段代码实现的,而是通过一条CPU指令完成的,所以CAS操作是原子的,就可以在一定程度上回避线程安全问题,所以我们在解决线程安全问题除了加锁之外,又有了一个新思路。

 但是我们可以通改CAS伪代码来帮助我们理解这个特殊指令:

    boolean CAS(address, expectValue, swapValue) {if (&address == expectedValue){&address = swapValue;return true;}return false;}

2.CAS的应用场景

2.1 实现原子类

Java标准库里面提供的类

AtomicInteger count = new AtomicInteger(0);
count.getAndDecrement();

count.getAndDecrement();相当于i++

伪代码实现

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

现在假设有两个线程同时调用上面的getAndDecrement(),

1) 两个线程都读取 value 的值到 oldValue . (oldValue 是一个局部变量, 在栈上。   每个线程有自己的栈 )

 2)线程1先执行CAS操作,由于oldValue和value的值相同,直接进行对value的赋值。

 此时的value值变成1,但是CAS的返回值为true,所以oldValue的值仍然为0。

3) 线程 2 再执行 CAS 操作的时候 发现 oldValue value 不相等 不能进行赋值。 因此需要进入循环。

循环里重新读取 value 的值赋给 oldValue。

4) 线程 2 接下来第二次执行 CAS, 此时 oldValue value 相同 , 于是直接执行赋值操作。

此时的value值变成2,但是CAS的返回值为true,所以oldValue的值仍然为1.

5) 线程 1 和 线程 2 返回各自的 oldValue 的值即可。通过形如上述代码就可以实现一个原子类 不需要使用重量级锁 ,  就可以高效的完成多线程的自增操作。

2.2 实现自旋锁

实现自旋锁伪代码

public class SpinLock {private Thread owner = null;public void lock() {while (!CAS(this.owner, null, Thread.currentThread())) {}}public void unlock() {this.owner = null;}
}

private Thread owner = null;

这个代码的含义是当前锁是谁加的。

    public void lock() {
        while (!CAS(this.owner, null, Thread.currentThread())) {
        }
    }

检测当前的owner是否为null,如果为空,就将当前线程赋值给owner。如果赋值成功,则加锁完成,循环结束。如果当前锁已经被其他线程占用,CAS操作会失败,因为this.owner不是null。此时返回false,继续循环进行下一次判定。

3.CAS的典型问题:ABA问题 

它的核心思想是检查当前值与预期值是否相等,如果相等则进行交换操作。然而,ABA问题是一个潜在的问题,即在CAS操作过程中,一个变量的值被修改两次后又恢复到了原来的值,导致CAS误判为没有发生变化,这个问题就叫ABA问题。

虽然这个ABA情况,大部分情况下,其实不会对代码/逻辑产生太大影响,但是不排除一些极端情况,也有可能造成影响。举一个极端的例子:

在考虑使用CAS方式扣款的情况下,假设我现在需要取款500元,我的账户余额为1000元。当我按下取款按钮时,机器可能会卡住,如果我不小心多次按下按钮,可能会导致重复扣款的情况发生,如下图

在执行第二次CAS操作时,如果此时有人转账500元进来,账户余额仍然为1000元,CAS操作会继续扣款。

为了解决这个问题,我们可以引入一个版本号或时间戳的概念。每次对变量进行修改时,同时更新版本号或时间戳。在进行CAS操作时,除了比较当前值和预期值之外,还需要比较版本号或时间戳。只有当两者都匹配时,才认为变量没有被中途修改过,可以进行交换操作

例如,假设我们有一个变量value和一个对应的版本号version,初始值为1。当我们想要更新value时,首先获取当前的version,然后执行更新操作,并将version加1。在进行CAS操作时,我们需要同时比较valueversion。只有当valueversion都与预期值匹配时,才执行交换操作。

通过引入版本号或时间戳,我们可以解决ABA问题,确保在并发环境下的正确性。

这篇关于CAS理解和说明的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1137510

相关文章

Linux中shell解析脚本的通配符、元字符、转义符说明

《Linux中shell解析脚本的通配符、元字符、转义符说明》:本文主要介绍shell通配符、元字符、转义符以及shell解析脚本的过程,通配符用于路径扩展,元字符用于多命令分割,转义符用于将特殊... 目录一、linux shell通配符(wildcard)二、shell元字符(特殊字符 Meta)三、s

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

一文带你理解Python中import机制与importlib的妙用

《一文带你理解Python中import机制与importlib的妙用》在Python编程的世界里,import语句是开发者最常用的工具之一,它就像一把钥匙,打开了通往各种功能和库的大门,下面就跟随小... 目录一、python import机制概述1.1 import语句的基本用法1.2 模块缓存机制1.

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

深入理解Redis大key的危害及解决方案

《深入理解Redis大key的危害及解决方案》本文主要介绍了深入理解Redis大key的危害及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、背景二、什么是大key三、大key评价标准四、大key 产生的原因与场景五、大key影响与危

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

Redis分布式锁使用及说明

《Redis分布式锁使用及说明》本文总结了Redis和Zookeeper在高可用性和高一致性场景下的应用,并详细介绍了Redis的分布式锁实现方式,包括使用Lua脚本和续期机制,最后,提到了RedLo... 目录Redis分布式锁加锁方式怎么会解错锁?举个小案例吧解锁方式续期总结Redis分布式锁如果追求

结构体和联合体的区别及说明

《结构体和联合体的区别及说明》文章主要介绍了C语言中的结构体和联合体,结构体是一种自定义的复合数据类型,可以包含多个成员,每个成员可以是不同的数据类型,联合体是一种特殊的数据结构,可以在内存中共享同一... 目录结构体和联合体的区别1. 结构体(Struct)2. 联合体(Union)3. 联合体与结构体的

关于SpringBoot的spring.factories文件详细说明

《关于SpringBoot的spring.factories文件详细说明》spring.factories文件是SpringBoot自动配置机制的核心部分之一,它位于每个SpringBoot自动配置模... 目录前言一、基本结构二、常见的键EnableAutoConfigurationAutoConfigu

Zookeeper安装和配置说明

一、Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式。 ■ 单机模式:Zookeeper只运行在一台服务器上,适合测试环境; ■ 伪集群模式:就是在一台物理机上运行多个Zookeeper 实例; ■ 集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble) Zookeeper通过复制来实现