当前位置: 首页 > news >正文

CAS相关知识

什么是CAS

在Java中,CAS(Compare And Swap)是一种用于实现无锁并发控制的原子操作。以下是关于Java中CAS的详细解释:

一、CAS的基本概念
CAS操作包括三个关键参数:

内存位置V:这是要操作的变量的当前值所在的内存地址。
旧的预期值A:这是希望进行比较的变量的旧值。
新的值B:如果变量的当前值与预期值相等,希望将其更新为的新值。
CAS操作会比较内存位置V的值与预期值A,如果相等,则将新值B写入内存位置V;如果不相等,则不做任何操作。这个比较和更新的操作是一起完成的,因此具有原子性

比较和更新的操作是一起完成的,因此具有原子性 是如何做到的

原子指令:
现代处理器提供了原子指令,这些指令在执行过程中不会被中断,从而保证了操作的原子性。
CAS操作通常基于处理器的CMPXCHG(Compare and Exchange)指令实现,该指令会比较内存中的值与预期值,如果相等则更新为新值,整个过程是原子的。
内存屏障:
原子指令通常伴随着内存屏障(Memory Barrier),以确保指令的执行顺序和可见性。
内存屏障会阻止处理器对指令进行重排序,从而确保CAS操作的前后指令按照程序员的预期顺序执行。
缓存一致性协议:
在多处理器系统中,==缓存一致性协议(如MESI、MOESI等)==确保了不同处理器之间的缓存数据保持一致。
当一个处理器执行CAS操作时,它会通过缓存一致性协议通知其他处理器更新其缓存中的数据,从而确保整个系统中数据的一致性。

总结:需要深入到 计算机指令或者是计算机硬件层面才能完全理解

java中的 aotmoicInt之类的类,是如何使用 CAS 的

其本质就是在一个循环里面不停的调用 cas
因为cas设置成功则成功,设置失败则什么也不做
为了能让 这个 整数值增加,所以需要需要一直循环执行 cas

CAS 为什么 比 synchronized 关键字快

最重要的就是 :CAS操作不会阻塞线程,可以避免线程切换和上下文切换的开销

CAS又会带来什么问题呢?

CAS操作存在ABA问题,即在比较和替换的过程中,变量的值可能经历了从A到B再到A的变化,但CAS操作无法检测到这种变化。为了解决这个问题,可以使用带有版本号的原子变量类(如AtomicStampedReference)来确保变量的正确性。

在CAS操作失败时,通常会通过循环不断尝试执行CAS操作,直到成功为止。这种方式可能会消耗一定的CPU资源,但在某些情况下可以提高系统的性能。

何时选择 cas 何时选择 synchronized

选择CAS的情况:

高并发读,低并发写:
如果你的应用场景中读操作非常频繁,而写操作相对较少,那么CAS可能是一个更好的选择。因为它避免了锁的开销,可以在高并发读的情况下提供更好的性能。
对性能有极高要求:
在一些对性能要求极高的场景下,如高频交易系统或实时计算应用,CAS的无锁特性可以显著减少线程间的竞争和上下文切换,从而提高性能。
需要避免死锁的时候
使用锁(如synchronized)时,如果锁的顺序不当或存在循环等待的情况,可能会导致死锁。而CAS操作则不会引发死锁问题,因为它不涉及锁的持有和释放。
细粒度锁:
当需要对某个对象的某个字段进行细粒度锁定时,CAS可能是一个更好的选择。它允许你以原子操作的方式更新字段,而不需要锁定整个对象。

选择synchronized的情况:

高并发写:
如果你的应用场景中写操作非常频繁,那么synchronized可能是一个更好的选择。因为锁可以确保数据的一致性和正确性,防止多个线程同时修改共享资源而导致的数据冲突。
代码可读性和维护性
synchronized关键字在Java中是一种非常常见的同步机制,它的语义清晰易懂,对于维护代码和团队协作来说更为方便。而CAS操作则相对复杂一些,需要理解其背后的原子性和无锁机制。
需要保证数据一致性:
在一些对数据一致性要求非常高的场景下,如银行账户操作或分布式事务处理中,使用锁可以确保数据的一致性和正确性。而CAS操作虽然可以避免锁的开销,但在某些极端情况下可能会导致数据不一致的问题(如ABA问题)。
简化编程模型:
对于一些简单的同步需求,使用synchronized关键字可以简化编程模型。它提供了一种简单直观的方式来确保线程安全,而不需要深入了解底层原子操作或并发控制机制。

synchronized锁我记得是分层级的,一开始是无锁,然后是轻量级锁,最后是重量级锁 是么?

无锁状态 这是对象的初始状态,表示没有任何线程持有该对象的锁。
偏向锁 偏向锁是为了优化只有一个线程访问同步块的场景。当一个线程首次获取锁时,锁会进入偏向锁状态,并在对象头中记录持有锁的线程ID。此后,该线程再次获取锁时,只需比较对象头中的线程ID,无需进行额外的CAS操作,从而降低了获取锁的开销。如果其他线程尝试获取偏向锁,则偏向锁会被撤销,并可能升级为轻量级锁或重量级锁。
轻量级锁 轻量级锁是为了在线程交替访问同步块时提高性能。当多个线程竞争偏向锁导致偏向锁被撤销时,锁会进入轻量级锁状态。轻量级锁通过自旋的方式尝试获取锁,如果自旋成功,则线程获取锁并继续执行;如果自旋失败,则锁会膨胀为重量级锁。轻量级锁减少了线程的阻塞和唤醒操作,从而提高了性能。
重量级锁 重量级锁是传统的锁机制,当轻量级锁自旋次数达到阈值或竞争过于激烈时,锁会膨胀为重量级锁。重量级锁依赖操作系统的MutexLock实现,线程在获取锁失败后会进入阻塞状态,等待锁释放后被唤醒。重量级锁的性能开销较大,因为它涉及到线程的阻塞和唤醒操作,以及用户态和内核态之间的转换。

此外,锁的状态升级是不可逆的,即锁只能从低级别状态升级到高级别状态,不能降级
因此,在使用synchronized锁时,应尽量避免多线程同时竞争锁,以减少锁升级带来的性能开销。

synchronized 轻量级锁使用的是CAS原理,那么什么情况下会升级重量级锁呢?

自旋次数超过阈值:

在JVM中,轻量级锁默认会尝试自旋一定次数以获取锁。这个自旋次数是一个阈值,如果线程在自旋过程中未能成功获取锁,并且自旋次数超过了这个阈值,那么轻量级锁会升级为重量级锁。
自旋次数的阈值在不同的JVM版本中可能有所不同。例如,在某些版本中,这个阈值可能是10次,此外,JVM还提供了参数(如-XX:PreBlockSpin)来调整这个阈值。

CPU资源消耗过高:

除了自旋次数外,JVM还会考虑CPU资源的消耗情况。如果自旋的线程数量过多,或者自旋时间过长,导致CPU资源消耗过高,那么JVM也可能会将轻量级锁升级为重量级锁。
特别是在多核CPU环境中,如果自旋的线程数量超过了CPU核心数的一半,那么升级为重量级锁的可能性会增加。

cas 能使用在对象上么?

可以的,java中提供了 atomicReference 类,就可以对。对象进行原子操作
不仅仅是只能对基本类型进行操作


http://www.mrgr.cn/news/51375.html

相关文章:

  • simpleITK和itk获取mask图像轮廓
  • 实战篇:(十一)JavaScript 网页设计案例:使用 Canvas 实现趣味打气球小游戏
  • 深度解析 Redis 存储结构及其高效性背后的机制
  • ESB服务集成是什么?如何运作的?有什么优势?
  • 大健康创新企业:私域流量与绿色积分共铸销售飞跃
  • SpringMVC源码-接口请求执行流程,包含九大内置组件的实例化初始化,拦截器调用,页面渲染等源码讲解
  • JavaSE——集合9:Map接口实现类—HashMap(重要!!!)
  • 快速创建品牌百度百科词条
  • 三类非常重要的约定管辖的法律效力
  • 9月份最新海关数据公布,增长6.2%
  • 2024双十一养猫清单给你们整理出来了高性价比盲抄作业不踩雷
  • 绕过MIME-Type验证
  • yolo笔记
  • 【C++】—通俗易懂的理解C++中的模板
  • 猫鼠游戏: KaijiK病毒入侵溯源分析
  • 宝宝学画画 4.3.0 |专为儿童设计的绘画启蒙软件
  • 无人机搭载激光雷达在地形测绘中的多元应用
  • 【FP60】林业害虫数据集——目标检测、图像分类
  • [NOIP2017]逛公园
  • 施磊C++ | 进阶学习笔记 | 5.设计模式