原子操作CAS

简介: 原子操作CAS

CAS

悲观锁

具有强烈的独占和排他特性。在有悲观锁的情况下,对数据进行处理,数据会处于锁定状态。前面讲到的synchronized同一时间只允许一个线程访问某块资源,其他线程处于阻塞状态,就是一个独占锁,是悲观锁中的一种。悲观锁适用于写操作比较多的场景。

乐观锁

对数据有更加宽松的加锁机制,允许多个线程同时访问对某块资源,一般通过版本号机制+CAS来实现。乐观锁适用于读操作比较多的场景。

CAS原理

CAS目的:保证在同一时间,只有一个线程能够更新值。

CAS基本流程:

  • 读取内存(地址i)中共享变量的值A,作为旧址
  • 业务逻辑处理得到值B
  • 读取相同共享变量(地址i)的值C,作为新值
  • 比较A和C是否相等
  • 相等就修改变量(地址)的值为B
  • 不等就自旋从第一步开始即Retry-Loop实现

在这个过程中,CPU会通过总线锁定机制来保证CAS操作的原子性,即在CAS操作期间,其他线程无法访问被操作的内存地址。由CPU底层硬件保证的。

对于Retry-Loop,感觉其实和锁什么什么两样。只是这种“锁”的粒度变小了,主要是“锁”关键资源,而不是整个数据结构。

自旋锁的实现依赖于CAS(Compare and Swap)操作,这是一种硬件级别的原子操作。

实现

CAS(Compare-and-Swap)通常使用类似cmpxchg指令实现的,cmpxchg(Compare-and-Exchange)指令是一种原子操作的CPU指令。例如

unsigned long cmpxchg(void *addr, unsigned long _old, unsigned long _new)
{
  int *a = addr; //或者用volatile int a;
  if(*a == _old){
    *a = _new;
  }
  return _old;
}

cmpxchg是设置一个新值,返回旧值。返回旧值可以做一些其他的业务操作。

CAS也是设置一个新值,但是可以自定义返回一个bool量。

例如:

bool compare_and_swap (int *addr, int oldval, int newval)
{
  if ( *addr != oldval ) {
      return false;
  }
  *addr = newval;
  return true;
}

volatile

内存中value值通过volatile进行修饰,保证了该属性值的线程可见性。在多并发的情况下,一个线程的修改,可以保证到其他线程立马看到修改后的值。

ABA问题

虽然使用CAS可以实现非阻塞式的原子性操作,但是会产生ABA问题,ABA问题出现的基本流程:

  • 进程P1在共享变量中读到值为A;
  • P1被抢占了,进程P2执行;
  • P2把共享变量里的值从A改成了B,再改回到A,此时被P1抢占;
  • P1回来看到共享变量里的值没有被改变,于是继续执行;

虽然P1以为变量值没有改变,继续执行了,但是这个会引发一些潜在的问题。ABA问题最容易发生在lock free的算法中的,CAS首当其冲,因为CAS判断的是指针的地址。如果这个地址被重用了呢,问题就很大了(地址被重用是很经常发生的,一个内存分配后释放了,再分配,很有可能还是原来的地址)。

ABA问题的解决思路就是使用版本号:在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么A->B->A就会变成1A->2B->3A。

目录
相关文章
|
4月前
|
Java 开发者
重学Java基础篇—Java类加载顺序深度解析
本文全面解析Java类的生命周期与加载顺序,涵盖从加载到卸载的七个阶段,并深入探讨初始化阶段的执行规则。通过单类、继承体系的实例分析,明确静态与实例初始化的顺序。同时,列举六种触发初始化的场景及特殊场景处理(如接口初始化)。提供类加载完整流程图与记忆口诀,助于理解复杂初始化逻辑。此外,针对空指针异常等问题提出排查方案,并给出最佳实践建议,帮助开发者优化程序设计、定位BUG及理解框架机制。最后扩展讲解类加载器层次与双亲委派机制,为深入研究奠定基础。
133 0
|
设计模式 数据可视化 测试技术
实践中的面向对象的例子
【7月更文挑战第1天】本文介绍面向对象编程注重代码的可理解性、重用和维护。例如,设计一个显示时间、温度等的设备,用户无需关心内部工作,这就是封装;如果需要多个设备,可通过多态创建不同实例;而继承则允许共享通用功能,如所有时钟都继承自计时器基类。
352 0
实践中的面向对象的例子
|
10月前
|
存储 NoSQL Redis
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
Redis持久化、RDB和AOF方案、Redis主从集群、哨兵、分片集群、散列插槽、自动手动故障转移
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
|
应用服务中间件 Linux nginx
dockerHosts文件无法外面加载
dockerHosts文件无法外面加载
167 0
|
Java 开发工具 计算机视觉
Java使用OpenCV3.2实现视频读取与播放
Java使用OpenCV3.2实现视频读取与播放
170 0
|
存储 编解码 网络安全
基于AutoJs实现的薅羊毛专业版第五次大更新
基于AutoJs实现的薅羊毛专业版第五次大更新
180 0
|
C语言 Perl
西门子S7-1200实例,电动机起保停控制
前面我们介绍了西门子S7-1200的硬件产品和编程软件的使用,下面通过一个电动机起保停控制的实例,介绍S7-1200的使用方法,按下瞬时启动按钮I0.6,电动机Q0.0启动,按下瞬时停止按钮I0.7,电动机Q0.0停止。
西门子S7-1200实例,电动机起保停控制
|
前端开发 芯片
【芯片前端】所以说,一直以来我理解的set_multicycle_path -hold都是错的?
【芯片前端】所以说,一直以来我理解的set_multicycle_path -hold都是错的?
282 0
|
存储 弹性计算 虚拟化
基于阿里云eRDMA的GPU实例大幅提升多机训练性能
2023年3月23日14:00(中国时间),NVIDIA GTC开发者大会,阿里云开发者社区观看入口正式开放,阿里云高级技术专家李伟男;阿里云弹性计算产品专家宋迪共同带来了题为《基于阿里云eRDMA的GPU实例大幅提升多机训练性能》的分享
基于阿里云eRDMA的GPU实例大幅提升多机训练性能
|
jenkins Shell 持续交付
jenkins权限问题
jenkins权限问题
308 0